Skip to content

SP-1: harness protocol v0, conformance kit, harness-fake - #79

Merged
adbarc92 merged 18 commits into
mainfrom
feat/harness-protocol-sp1
Sep 15, 2026
Merged

adbarc92 merged 18 commits into
mainfrom
feat/harness-protocol-sp1

Conversation

@adbarc92

Copy link
Copy Markdown
Owner

Implements SP-1 of the swappable-harness design, NEXUS docs/specs/2026-09-14-swappable-harness-design.md (§3 protocol v0; §6 items 1, 2, 7). Plan: docs/superpowers/plans/2026-09-14-harness-protocol-sp1.md. fleet-core and fleetd are untouched.

What's in it

  • crates/harness-protocol: wire types for a JSON-RPC 2.0, newline-delimited, stdio protocol between the control plane and a harness (initialize, unit/start, unit/event, gate/request, unit/halt|resume|abandon, unit/result). Also:
    • an RPC envelope and a line codec;
    • a JSON Schema contract, pinned by canonical SHA-256 (51c64132…9463), whose schema carries a method table;
    • a README for harness authors, including a rule → violation table.
  • crates/harness-conformance:
    • a kit that spawns any harness binary and checks it from outside, across six cases: version mismatch, T1 happy path, oracle gate approve/reject, halt, abandon;
    • the harness-conformance CLI (exit 0 / 1 / 2);
    • harness-fake, a scripted reference harness whose misbehaviour modes prove the kit catches each violation.
  • CI: a new harness conformance job that runs the kit against harness-fake.

Verification (at the head of this branch)

  • cargo fmt --all -- --check and cargo clippy --workspace --all-targets -- -D warnings: clean.
  • cargo test --workspace: 22 suites, 166 passed, 0 failed, 3 ignored (pre-existing fleetd Docker ITs), 0 warnings.
  • harness-conformance -- harness-fake: 6 passed, 0 skipped, 0 failed, exit 0.
  • The contract hash is identical under Rust and Node canonicalisation.

How it was built

Nine tasks, each reviewed for spec compliance and quality before the next. Then a whole-branch review ("with fixes") and one fix wave:

  • gate_approved_t2 no longer passes when the gate was never reached;
  • an interrupt must be answered and the process must exit within grace;
  • interrupts are delivered while a gate is pending, and a case is SKIPped when no interrupt could be sent;
  • harness stderr is passed through;
  • the README spells out the kit's rules;
  • Metric is documented as incremental, and the contract was re-pinned once.

A scoped re-review confirmed every finding addressed.

Deliberately not in this PR

  • Plan Task 10: registering the contract in NEXUS docs/contracts/. It waits for nexus#26 to merge, and must use hash 51c64132….
  • SP-2 prerequisites found in review: move violation detection into a shared, runtime-agnostic protocol monitor for fleetd's supervisor; add a work-order override (plus a sandbox repo) before a real harness joins this CI job.
  • Spec amendments for nexus#26: the metering case's wording, the tagged delivery evidence shape, and a possible blocked event.
  • Known minor: an unreachable match arm in interrupt_case, to be rewritten with SP-2's monitor.

After merge

Once the harness conformance check has run on this PR, make it a required status check on main (spec §6.7, the GAP-133 lesson). That is a repository-settings change, left for an explicit go-ahead.

…r reached

A harness that ended failed or no_change without sending gate/request fell through to PASS. Such a run now reports SKIP, since the approval path was never exercised. pr_open without a gate request stays Fail(GateNotRequested). harness-fake gains fail_before_gate mode to prove it.
…xit within grace

Once unit/halt or unit/abandon is sent, the receive deadline shrinks to min(wall clock, now + grace). A timeout from then on is InterruptNotHonored, not WallClockExceeded. EOF counts as honoured only if the interrupt's response arrived first and the process exits within grace. harness-fake gains ack_halt_linger and silent_halt_exit modes to prove both gaps.
…g; skip when none was sent

With gates: [oracle], halt and abandon now run a T2 unit and send the interrupt in place of answering gate/request (GatePolicy::Hold). A harness blocked on its gate must handle it, which removes the race with a fast harness. Without an oracle gate, the T1 path is unchanged: the interrupt follows the first unit/event. Transcript records interrupt_sent, and a unit/result that arrives before any interrupt could be sent is now SKIP, not a false FAIL. harness-fake gains result_without_events mode.
The kit spawned harnesses with stderr set to null, so a harness author never saw their own diagnostics when a case failed. stderr is now inherited. harness-fake writes nothing to stderr, so test output stays pristine.
Adds a rule-to-violation table, including the T1 gate rule that is stricter than the spec, and notes that harness stderr is passed through. Also warns authors to exec their harness rather than wrap it.
…-pin the contract

UnitEvent::Metric now documents that its figures are incremental since the previous metric for the unit. ProtocolSchema carries a method table giving each method's direction, kind, and params/result types. Both land in the schema as descriptions. The contract is re-blessed and re-pinned: the Rust and Node canonical digests match at 51c64132b2d3d898791f064820ffb92fdbd2b0d36f71913bd8d85e48f1df9463. committed_contract_hash_is_pinned now returns early during a bless run, so it cannot race the rewrite.
…, fix CI header

harness-conformance now exits 2 on --grace-secs 0, because a zero grace fails every case. The unused serde_json dependency is removed. The ci.yml header comment names all four root-workspace crates.
@adbarc92
adbarc92 merged commit 848332e into main Sep 15, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant