Skip to content

The box seam's two wire formats get an owner and a round-trip suite #30

Description

@JacobStephens2

The Progress Log record and the LOOP_RUN_* summary are the only two things that cross the SSH seam between the box and the Selector, and both are conventions with a writer and re-implementing readers - no shared definition, and one adapter already drifted. Out of the 2026-08-31 architecture review of the Loop (lab/single-user-factory).

The friction

The Progress Log record. run.sh emits ~20 literal line formats (the Run and Iteration headings, - Agent exit:, - Turn bound:, - No-op Iteration:, - Head:, the contract summary, the ended block). selector/watcher.py:61-77 re-implements nine of them as regexes and says so at :55-60: "Copied rather than sourced." Only the two headings are genuinely shared, through contract.sh:186-187, whose comment states the principle this issue generalises: "Two scripts agreeing on a literal string by both spelling it out is a seam that breaks silently."

An invariant the reader depends on exists only on the reader's side: a record is the run of - lines under the heading and ends at the first line that is not one (watcher.py:105-114). What makes that true is the blank line at run.sh:434, and neither run.sh nor loop/tests/loop.bats knows it is providing a guarantee - the bats suite asserts substrings, never the record's shape or the terminating blank line. notes/selector-watcher-evidence.md records two near-misses of exactly this class (agent-written headings nearly made every Iteration report one late; an agent-written Run heading would have dropped the block whole), both fixed on the reader's side only.

The LOOP_RUN_* summary. run.sh:643-649 emits six keys; parsers of the convention: dispatch.py:126-141 and :281-294, run.sh:595 itself, and two bats helpers. Nothing states the field set or the value vocabulary. The bound vocabulary is partially re-enumerated on the far side at cycle.py:106 (RUN_FAILURE_BOUNDS).

The drift, already shipped: selector/preview-sources/box.sh:31 - the second adapter at this seam - puts a URL in LOOP_RUN_PROPOSAL (whose vocabulary in run.sh is skipped|proposed|failed) and omits LOOP_PROPOSE_URL, the key dispatch.py:292 actually reads for the Proposal. So every Attended Preview Run is journaled no-proposal - a failed attempt - whatever the fixture intends. Contained to previews, but it is precisely the silent misclassification the block exists to prevent, and it demonstrates that a second adapter cannot stay conformant with nothing to conform to. Fixing that line is the first concrete deliverable here whatever shape the rest takes.

The deepening

The formats become the seam's declared interface rather than a convention:

• The line formats and the summary's field set + value vocabularies get one declared home, extending the precedent contract.sh already sets with the two headings.
• A round-trip conformance suite: fixtures a real run.sh writes (fake agent, collapsed clocks - the existing bats scaffolding already produces this), parsed by the real watcher.py and dispatch.py parsers. One suite proves writer and readers agree, and grades every adapter at the seam, preview-sources/box.sh included.
• The writer's suite asserts the record's shape - the terminating blank line becomes a checked property instead of an accident.

Wants grilling before building

Cross-language (bash writer, Python readers), so "one owner" cannot be one sourced file; the candidate mechanism is shared declaration + shared fixtures, and the interview should settle: where the declaration lives, whether the fixtures are generated per-run or checked in (selector/tests/fixtures/box-progress-run-648.md already exists as a fourth copy of the format), and how far the summary's value vocabularies should be typed on the Python side.


Originally filed as Educational-Travel-Adventures/orchestration#317.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-grillingA raw idea captured; wants a grilling before anyone builds from it

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions