Chapter 09
Surface topology scanner
The scanner compares what you declared in your surface contract against what the lens actually observed in traffic, and returns the gaps: dimensions you promised the lens would see and it never did, dimensions the lens has been seeing that you never declared, and surfaces that look like they've gone quiet. There's also a bootstrap mode that reads recent traffic and proposes candidate dimensions to add to a new contract.
What it is
Three endpoints, each doing one job:
- Structural inventory — you tell the scanner what your codebase says exists (surface ids you can enumerate, or a dispatch map). This becomes the third leg — alongside "declared on the contract" and "observed in traffic" — that the scan can reason about.
- Scan — the scanner reads events over a window, joins them against the active contract and any recent structural inventory, and returns the coverage gaps as a set-difference across the three sources.
- Bootstrap — when you have traffic against a surface but no contract entry yet, bootstrap reads the traffic and proposes dimensions to declare.
Why it matters
A contract that drifts away from reality is a contract that stops helping. Two ways it drifts:
- A dimension gets added in code and the contract never gets updated. The lens sees it, the contract doesn't; downstream analyses skip it.
- A dimension gets removed in code and the contract still declares it. Downstream analyses keep looking for it and quietly report it as always-null.
The scanner surfaces both directions at read time, so contract maintenance becomes a scheduled operator task with a concrete work-list, not an ad-hoc audit.
How to use it
1. Declare a structural inventory
At startup, or on each deploy, tell the scanner what your codebase currently knows about. Two shapes are accepted:
surface-ids— a flat list of the surface ids your code can enumerate.dispatch-map— a dispatch table mapping keys (intents, tools, or any other routing key) to surface ids.
POST /lens/topology/structural-inventory
x-holonograph-run-mode: production
Content-Type: application/json
{
"agentId": "billing-triage",
"consumerId": "billing-triage-agent",
"inventoryKind": "surface-ids",
"surfaceIds": ["classify-intent", "review-flagged-charge", "escalate-to-human"],
"capturedAt": "2026-07-05T18:00:00Z"
}
Response:
{
"inventoryId": "inv_01H...",
"consumerId": "billing-triage-agent",
"capturedAt": "2026-07-05T18:00:00Z",
"created": true
}
2. Run a scan
A scan reads events over a window and returns a coverage report. Run it on a schedule (nightly, per deploy) or on-demand.
POST /lens/topology/scan
x-holonograph-run-mode: production
Content-Type: application/json
{
"agentId": "billing-triage",
"since": "2026-06-01T00:00:00Z",
"until": "2026-07-05T00:00:00Z",
"record": true
}
Set record: true to persist the scan result as an event of its own — useful for tracking how coverage changes over time.
3. Bootstrap a new surface's dimensions
When you're onboarding a new surface — traffic is flowing, but the contract entry is bare — bootstrap reads the traffic and proposes dimensions.
POST /lens/topology/bootstrap
x-holonograph-run-mode: production
Content-Type: application/json
{
"surfaceId": "review-flagged-charge",
"since": "2026-06-15T00:00:00Z",
"until": "2026-07-05T00:00:00Z"
}
Each candidate comes back with an inference label:
deterministic— the dimension appeared consistently and with a stable shape across the window. Safe to declare.lowConfidence— the dimension appeared, but sparsely or with an unstable shape. Worth reviewing before adding to the contract.
Reading the output
The scan report is a set-difference across three sources — the contract's declared, the events' observed, and (if you captured one) the code's structural inventory. The scanner returns per-surface lattices with these fields:
| Field | What it tells you |
|---|---|
declaredUnobserved | Dimensions on the contract that the lens has not seen in the window. Either they're broken in code, or the contract is stale. |
observedUndeclared | Dimensions the lens has seen that the contract does not declare. Add them to the contract or stop emitting them. |
declaredUnstructural | Declared on the contract but not present in the structural inventory. Strong retirement candidate — the code no longer references it. |
structuralUnfired | Present in the structural inventory but never observed. Wired but not exercised — possibly dead paths. |
forwardDeclaredAbsent | Declared in the contract for a future rollout, not yet observed. Expected empty until the feature ships. |
deprecatedAbsent | Marked deprecated on the contract and no longer observed — a clean retirement completed. |
Acting on the report
The usual cadence: a scan runs nightly, its report gets read by an operator, undeclared dimensions get added to the contract, retirement candidates get retired (see the supersededBy mechanism in Surface contracts). Over time, "clean scan" becomes the deploy readiness signal for contract changes.
Reference
Endpoints
| Method & path | Purpose |
|---|---|
POST /lens/topology/structural-inventory | Declare what your codebase enumerates. |
POST /lens/topology/scan | Compare declared vs observed vs enumerated, return the coverage report. |
POST /lens/topology/bootstrap | Propose candidate dimensions for a surface based on recent traffic. |
POST /lens/topology/structural-inventory — request
| Field | Shape | Notes |
|---|---|---|
agentId | string (req) | The agent this inventory belongs to. |
consumerId | string (opt) | Identifier of the code that's declaring the inventory (useful when multiple deployments feed one contract). |
capturedAt | ISO 8601 (opt) | When the inventory was taken. Defaults to now. |
inventoryKind | enum (req) | surface-ids or dispatch-map. |
surfaceIds | string[] (opt) | Required when inventoryKind = "surface-ids". |
dispatchMap | object (opt) | Required when inventoryKind = "dispatch-map". |
artifactKind | string (opt) | Freeform label for the source artifact (e.g. codegen, handwritten). |
POST /lens/topology/scan — request
| Field | Shape | Notes |
|---|---|---|
agentId | string (opt) | Restrict the scan to one agent. Omit to scan all. |
since | ISO 8601 (opt) | Inclusive lower bound on events considered. |
until | ISO 8601 (opt) | Exclusive upper bound on events considered. |
asOf | ISO 8601 (opt) | Contract and inventory versions to compare against (defaults to latest). |
record | boolean (opt) | Persist the scan as an event. |
artifactKind | string (opt) | Restrict to inventories with this kind label. |
POST /lens/topology/bootstrap — request
| Field | Shape | Notes |
|---|---|---|
surfaceId | string (req) | The surface to propose candidates for. |
since | ISO 8601 (opt) | Inclusive lower bound on the traffic window. |
until | ISO 8601 (opt) | Exclusive upper bound. |