Skip to content

Surface Goldens

Trace.surface freezes the prompt surface a run used: system instructions, tool definitions, and framework-injected text beyond the conversation itself. It exists for forensics. Every run should carry the steering surface it ran against when the runtime can report one, so later triage does not reconstruct prompts from git archaeology, container images, and deployment memory.

Surface capture is evidence about the run, not the behavior being tested. A broken surface probe should be loud, but it should not destroy an expensive bench run.

The four surface states

Trace.surface is captured once per run, after reset_state() and before the first user turn. A captured surface block has one of four status values:

Status Meaning
rendered Driver-side truth. The runtime rendered the prompt surface itself, so the block is the surface the model was actually driven with. Scripted or worker-side runtimes, including in_memory when given a scripted surface, can use this label.
reported Endpoint-reported configuration, usually from an external Contract C runtime via /wt/surface. A driver cannot verify what the model saw through an inject boundary, so reported is permanent labeling, not a transitional state waiting to become truth.
unavailable Honest absence. The handle or endpoint cannot report a surface. For Contract C, a 404 or 501 from /wt/surface conforms and records this state.
invalid The surface route existed but returned a malformed response, raised, or failed validation. This is a probe-level failure: the run proceeds, but surface gates treat it as hard failure. Strict gate, resilient run.

If a handle has no surface-introspection method at all, the trace may carry no surface block. That is different from a probed status: unavailable, but both mean there is no surface to record as a golden.

Record, diff, check

The wt surface command probes a runtime without running scenarios or making a model call. It provisions the runtime, resets it, asks for the surface, tears it down, and compares the result with a golden.

Record the first golden:

uv run wt surface record --runtime <your-runtime> --golden windtunnel/surface.golden.json

Review changes during development:

uv run wt surface diff --runtime <your-runtime> --golden windtunnel/surface.golden.json

Gate CI:

uv run wt surface check --runtime <your-runtime> --golden windtunnel/surface.golden.json

Use --soul PATH when the runtime should be probed with the same SOUL/system prompt override you pass to wt run. Use --label LABEL when you want the probe variant recorded under a specific label. The default golden path is surface.golden.json; pass --golden so teams can put goldens beside the bench configuration they govern.

The golden format is hashes at its core:

{
  "windtunnel_surface_golden": 1,
  "status": "reported",
  "system_instructions": "sha256:...",
  "tool_order": ["lookup_invoice", "draft_note"],
  "tool_definitions": {
    "lookup_invoice": "sha256:...",
    "draft_note": "sha256:..."
  },
  "extra_segments": {
    "tool_progress": "sha256:..."
  }
}

No prompt text is stored by default. That is the point: hash-only goldens are committable even when the real prompt surface is private IP.

--store-text is an explicit opt-in for teams whose prompts are public and who want textual PR review:

uv run wt surface record --runtime <your-runtime> --golden windtunnel/surface.golden.json --store-text

That embeds the complete prompt surface in the golden under a human-facing text sidecar plus a sensitivity warning. Treat that file as sensitively as the system prompt itself. Comparison still reads hashes only; the text is for humans.

Semantics to keep straight

A surface hash change means: run the bench before merge. It is a tripwire for steering drift.

An unchanged hash proves nothing. Harness code, model behavior, tool implementation, upstream latency, and fixture state can all move while the prompt text stays identical. Passing wt surface check is never a skip token for the bench.

wt surface diff is informative. It prints per-segment changes and exits 0 after a successful comparison, even when hashes changed.

wt surface check is the gate. It exits nonzero on any changed hash, on an invalid current surface, or on an absent current surface when the golden promises one. There is deliberately no warn-vs-error knob. If the golden says "this runtime has a surface," then failing to produce that surface is a change requiring attention.

CI wiring

A minimal CI shape is:

jobs:
  surface:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v5
      - run: uv sync
      - run: uv run wt surface check --runtime <your-runtime> --golden windtunnel/surface.golden.json

On failure, do not bless the new hash reflexively. Review the diff, run the bench against the changed surface, and then re-record the golden:

uv run wt surface diff --runtime <your-runtime> --golden windtunnel/surface.golden.json
uv run wt run --runtime <your-runtime> --runs 5 --label surface-review
uv run wt surface record --runtime <your-runtime> --golden windtunnel/surface.golden.json

Endpoint authors implementing /wt/surface should follow the Contract C surface shape in Design 0002: inject protocol.