Ledger Gateway Override

← Back to Enforcement Layer ledger-gateway-override.md

Ledger Gateway Override

This skill overrides all inline HubSpot write instructions in slash commands. Load this BEFORE executing any HubSpot writes. Governance overrides command text.

Rule

Every HubSpot write — Listing creation, object updates, association creation, engagement creation, custom event fire, property creation — MUST be routed through Ledger.

Slash commands contain inline mcp__hubspot__hubspot-batch-create-objects, hubspot-batch-update-objects, hubspot-create-engagement, and hubspot-batch-create-associations instructions. These predate Ledger and describe WHAT to write, not HOW to execute. Treat them as write specifications, not executable instructions.

Custom events (Sentinel Phase A) are first-class HubSpot write operations subject to the same validation: event-name whitelist, primary-object type matching, property schema compliance, owner attribution, and idempotency. Ledger validates all 5 constraints before fire.

Routing Pattern

When a slash command specifies a HubSpot write, spawn Ledger:

Agent(subagent_type: "ledger", prompt: "
  Write request from {command name}:
  - Operation: {create | update | associate | engagement | custom-event}
  - Object type: {listings | appointments | contacts | notes | interest | deliverable | etc.}
  - Properties: {copy the properties block from the command}
  - Associations: {copy the association block from the command}
  - Event name (if custom-event): {event name from custom-events.json}
  - Event properties (if custom-event): {copy properties block}
  Validate against property-index and custom-events.json before writing. Return created/updated IDs.
")

What Ledger Does

  1. Loads agents/hubspot-write-gateway/AGENT.md for full context
  2. Runs ToolSearch to load HubSpot MCP write tool schemas
  3. Validates properties against skills/hubspot/property-index/ files
  4. Validates association types against skills/hubspot/property-index/associations.json
  5. Executes the write via local MCP (mcp__hubspot__hubspot-*)
  6. Returns confirmed IDs to the calling command

Fallback

If Ledger agent spawn fails (tool unavailable, MCP down), use the HubSpot CLI as a validated fallback:

node scripts/hubspot/api.js create {object} --props '{...}'
node scripts/hubspot/api.js associate {from_type} {from_id} {to_type} {to_id} --type {typeId}

Even in fallback, validate properties against property-index before writing.

Custom Event Validation Contract

Custom events (Sentinel Phase A) validate against a 5-point contract:

# Constraint Validation Source of Truth
1 Event-name whitelist Event name must exist in registry skills/hubspot/property-index/custom-events.json (12 registered templates)
2 Primary-object type Primary object type (COMPANY or CONTACT) must match template definition Template's primaryObject field
3 Property schema Property names must exist in template's propertyDefinitions; types must match (string/number/datetime) Template's propertyDefinitions array
4 Owner attribution practitioner_owner_id must be numeric string (Sentinel Phase A requirement) Matches regex ^\d+$
5 Idempotency Prevent duplicate fires within 60-second window using event name + primary_object_id + occurredAt Ledger local cache (CLI) or broker KV cache

Special case: signal_severity — HubSpot API defines as type: "string" (no enum support at definition time). Ledger enforces enum: low | medium | high | critical. CLI blocks invalid value; broker soft-checks; HubSpot rejects.

Failure codes:

  • custom_event_unknown_template — Event name not in registry
  • custom_event_primary_object_missing — Primary object missing or type mismatch
  • custom_event_property_not_in_schema — Property not in template definition
  • custom_event_property_type_mismatch — Property value doesn't match declared type
  • custom_event_owner_id_invalid — practitioner_owner_id invalid format
  • custom_event_signal_severity_invalid — signal_severity not one of low|medium|high|critical

Detection Triggers

If you catch yourself doing any of these, STOP and route through Ledger:

  • Calling ToolSearch to load hubspot-batch-create-objects or hubspot-batch-update-objects
  • Calling ToolSearch to load hubspot-create-engagement
  • Calling ToolSearch to load hubspot-batch-create-associations
  • Calling ToolSearch to load hubspot-custom-events or similar event-fire tool
  • Writing HubSpot CLI create/update/associate/custom-event commands directly

These are signs of Ledger bypass. The only agent that should load HubSpot write tool schemas is Ledger itself.