feat(sync): re-land cockpit mirror extract+diff as a sync channel#272
Merged
Conversation
tieubao
force-pushed
the
feat/cockpit-mirror-channel
branch
2 times, most recently
from
July 18, 2026 13:50
cab1619 to
da737f8
Compare
Port the two deterministic legs of the legacy board bridge into the sync
module as lib/sync/cockpit.py: multi-source EXTRACT (a boards.txt registry
plus each opted-in repo's active mega-goals) with origin-prefixed identity
(<repo>:ID-NNN, megagoals:<repo>/<slug>), and the keyed row_hash TRANSFORM
diff (create / unchanged / change / complete) where the git board always
wins. Carries over the two assets the port was required to keep: the
row_hash git-wins conflict rule and the live-probed Hermes reachable-state
map {triage, ready, blocked, done}.
The row_hash is byte-identical to the legacy board-mirror.sh engine, so the
existing bridge NDJSON snapshot is a format-compatible bearing interface for
a later cutover. Reachable via a new opt-in route: board mirror --engine
sync --dry-run runs the new planner; a bare --engine sync without --dry-run
refuses (exit 64) rather than silently no-op'ing, because the live Hermes
LOAD leg and two-way writeback are deferred and stay on the legacy engine,
which remains the default and keeps working.
Tests: lib/sync/tests/test_cockpit.py, 52 cases at 98% line coverage with
negative controls (idempotent second run, no re-complete of a done row,
shipped/dropped and opted-out exclusion, malformed-snapshot skip). Legacy
suite test-board-mirror.sh stays 72/72 (fold-in leaves the bridge untouched).
Apply architecture + advisor review findings on the cockpit channel: - Prefixed-id gap (load-bearing): the extract reused sync_core.parse_board, which matches bare ID-NNN only, so every prefixed row (BK-, DS-, DF-, ...) was silently dropped and would mass-COMPLETE at a snapshot cutover. Replace it with parse_cockpit_board, a faithful port of the legacy pb_rows plus column logic: honors [A-Z]+-[0-9]+ (BACKLOG_ID_RE override), splits on the raw pipe like the legacy awk, and is column-agnostic (item col 3, notes cols 4..NF-2). Extract is now byte-identical to board-mirror.sh on a prefixed-id fixture (verified with cmp). - Repo-root resolution now uses git rev-parse --show-toplevel (was a _meta path heuristic), so a root-level BACKLOG.md still finds _meta/megagoals. - board mirror --engine validates its value (bogus -> exit 64) instead of falling through to the legacy live engine on a typo. - Registry parser folds trailing tokens into the bridge column, matching the legacy read -r name path bridge (so "... on trailing" is not opted in). - Port the MIRROR_UNTRUSTED_* content markers as constants plus helpers so the deferred LOAD leg wraps card text by construction and does not drop the prompt-injection boundary; documented in the spec's deferred list. Tests grow to 62 cases (97% coverage) with prefixed-id, wide-table, BACKLOG_ID_RE, git-root, registry-folding, and marker coverage.
Apply the security review's two Medium findings:
- read_snapshot crashed on a valid-JSON-but-non-object line (null, 42, [1,2]):
json.loads succeeded, then .get("origin") raised AttributeError, killing the
whole run and contradicting the function's own "not fatal" contract. Skip any
non-dict parse result.
- The extract and plan --json paths print raw item/notes from contributor-
editable board rows. Emit an out-of-band stderr banner marking that content
as untrusted DATA (the SPEC-147 content-trust boundary), so an operator or
agent piping the dry-run output downstream gets the warning before the LOAD
leg's structural marking exists. The markers are deliberately NOT applied to
the plan fields (that would corrupt the plan the LOAD leg consumes and
double-mark card text; the LOAD leg marks at card build).
Tests: +7 cases (valid-JSON-non-object snapshot lines, banner on both output
paths); suite now 69 cockpit cases, sync suite 129 green.
tieubao
force-pushed
the
feat/cockpit-mirror-channel
branch
from
July 18, 2026 13:57
da737f8 to
704da7e
Compare
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
First slice of ID-290 / SPEC-002 P2: re-land the legacy
board mirrorbridge as a channel inside the sync module. Ports the two DETERMINISTIC legs intolib/sync/cockpit.py:boards.txtregistry (every opted-in repo'sBACKLOG.md+ its active_meta/megagoals/*/ROADMAP.md) into origin-keyed items (<repo>:<id>,megagoals:<repo>/<slug>), honoring the legacy[A-Z]+-[0-9]+id pattern so prefixed multi-repo boards (BK-,DS-,DF-, ...) pool without ID collisions.row_hashTRANSFORM/diff (create / unchanged / change / complete) where the git board always wins.Carries over the two assets the port was required to keep: the row_hash git-wins conflict rule and the live-probed Hermes reachable-state map
{triage, ready, blocked, done}. The extract is byte-identical toboard-mirror.sh(verified withcmpon a prefixed-id fixture), so the existing bridge NDJSON snapshot is a format-compatible bearing interface for the eventual cutover.Reachable via a new opt-in route:
board mirror --engine sync --dry-run. Legacy stays the default and untouched. A bare--engine syncwithout--dry-runrefuses (exit 64) rather than silently no-op'ing.Deferred (documented, still on the legacy engine which stays runnable)
The live Hermes LOAD leg, two-way writeback (SPEC-149), snapshot state-shape migration, named-profile config, and retiring
mirror/status/writebackto thin aliases. Security carry-over noted in the spec: the LOAD leg must wrap card text through the portedmark_untrusted_*markers.Why a slice, not the whole port
The legacy engine is ~1000 lines of bash with a live-Hermes LOAD leg and two-way writeback that cannot be CI-tested and are risky to rewrite blind. This slice lands the deterministic, fully-testable core plus origin identity (the P2 engine change everything else builds on) without touching the working live path.
Tests / verification
lib/sync/tests/test_cockpit.py: 62 cases, 97% line coverage, negative controls (idempotent re-run, no re-complete of a done row, shipped/dropped + opted-out exclusion, malformed-snapshot skip, prefixed-id, wide-table, registry trailing-token folding).cmp(incl. prefixed ids + megas).test-sync(122),test-board-mirror(72, legacy untouched),test-board(45),test-board-writeback(53),test-meta(698), shellcheck clean.Proof:
lib/sync/docs/proof-of-done.md. Spec:lib/sync/docs/specs/SPEC-002-sync-mesh.md(P2).