# The wire-contract gate, run against the tree at b7fb211 on 2026-08-08

Deliverable 1 of the G-1/R-260 session: the gate FAILING, before any field was fixed.
Captured verbatim. If this had been green, the gate would not work and that would be the finding.

```
wire-contract gate — 210 tag(s) checked across 3 declared wire(s); 51 skipped (generic / opaque / allowlisted)

  agent -> hub   (POST /host-report)
  the RECEIVER (hub) contains no occurrence of:
      applied_at                       (emitted at pbs_dr.applied_at)
      checked_at                       (emitted at guest_net.checked_at)
      cpu_temp_c                       (emitted at host.cpu_temp_c)
      damped                           (emitted at guest_net.guests.damped)
      dhclient_alive                   (emitted at guest_net.guests.dhclient_alive)
      disk_bytes                       (emitted at guests.spec.disk_bytes)
      guest_net                        (emitted at guest_net)
      has_route                        (emitted at guest_net.guests.has_route)
      heal_succeeded                   (emitted at guest_net.guests.heal_succeeded)
      healed_at                        (emitted at oob.healed_at)
      healed_recently                  (emitted at mgmt_plane.healed_recently)
      heals_last_hour                  (emitted at guest_net.guests.heals_last_hour)
      last_handshake_age_s             (emitted at wireguard.last_handshake_age_s)
      last_heal_at                     (emitted at guest_net.guests.last_heal_at)
      loadavg                          (emitted at host.loadavg)
      memory_bytes                     (emitted at guests.spec.memory_bytes)
      memory_total_bytes               (emitted at host.memory_total_bytes)
      memory_used_bytes                (emitted at host.memory_used_bytes)
      model_name                       (emitted at storage_targets.smart.model_name)
      mount_inventory                  (emitted at restore_tests.mount_inventory)
      mount_parity                     (emitted at restore_tests.mount_parity)
      operator_key_configured          (emitted at oob.operator_key_configured)
      selfupdate_pending               (emitted at selfupdate_pending)
      selfupdate_pending_version       (emitted at selfupdate_pending_version)
      uptime_seconds                   (emitted at host.uptime_seconds)
      wg_handshake_age_s               (emitted at oob.wg_handshake_age_s)

  controller -> hub   (POST /report)
  the RECEIVER (hub) contains no occurrence of:
      config_hash                      (emitted at config_hash)
      last_db_dump                     (emitted at backup.last_db_dump)
      last_integrity_check             (emitted at backup.last_integrity_check)
      load_avg_1                       (emitted at system.load_avg_1)
      load_avg_15                      (emitted at system.load_avg_15)
      load_avg_5                       (emitted at system.load_avg_5)
      memory_total_mb                  (emitted at system.memory_total_mb)
      memory_used_mb                   (emitted at system.memory_used_mb)
      migrated_to                      (emitted at storage.migrated_to)
      reporting_disabled               (emitted at reporting_disabled)
      stacks                           (emitted at stacks)
      temperature_celsius              (emitted at system.temperature_celsius)
      uptime_seconds                   (emitted at system.uptime_seconds)

  hub -> controller  (report ACK, `escrow` object)
  the RECEIVER (controller) contains no occurrence of:
      escrow_stale                     (emitted at escrow_stale)

WIRE-CONTRACT GATE FAILED: 40 emitted field(s) cannot be received.
A tag whose literal string occurs nowhere in the receiving repo cannot be decoded
by any struct, named or anonymous — encoding/json discards it on arrival.
Fix: model the field on the receiving side and say what consults it — or, if it is
deliberately not consumed, add it to ALLOWLIST WITH A REASON. Never a quiet skip.

Blind spots (a green is not full coverage — see the module docstring):
  generic tag names are not checked; reachability of a NAME is not use of a VALUE;
  only the declared ROOTS are covered (hub desired-state and the agent local API
  are NOT).
exit=1
```

## Self-test (a planted unreachable tag on a real root)
```
  planted an unreachable tag on agent HostReport -> gate exit 1, planted tag convicted: True
  unplanted tree -> gate exit 1
SELFTEST OK — the gate convicts a planted unreachable tag and the plant is the only difference.
exit=0
```

---

## ⚠ The search implementation changed AFTER this capture, and the capture was re-verified

The run above used `grep -rnE --include=…` to test whether a tag occurs in the receiving repo. That
**works on a workstation and returns nothing on the CI runner**, whose image carries python3 and git
and deliberately little else — its `grep` does not support `--include`. Empty stdout was then read as
"the tag is absent", so the gate convicted **all 174** checked tags and CI went red while the
pre-push hook was green (runs 260–262).

That is the gate silently reading a tool failure as a finding, which is worse than no gate, and it is
the error-swallowing this repo's rules forbid. The search is now **pure Python**: one token index per
receiving repo, no subprocess, no external dependency.

**This capture was NOT re-generated — it is re-verified**, which is the stronger claim. Every one of
the 40 fields recorded above was re-tested against the new implementation:

```
fields recorded in BEFORE.md: 40
agree=40 disagree=0
```

— i.e. the new implementation finds exactly the four this session fixed (`operator_key_configured`,
`wg_handshake_age_s`, `healed_at`, `escrow_stale`) present, and the other 36 still absent. **The
number 40 stands under both implementations**; only the mechanism and its portability changed.

The whole-token property also survives by construction: a token index treats `healed_at` and
`privsep_healed_at` as distinct tokens, so the substring false negative that the control caught
cannot come back.
