Store a digest of the map file on implementations at open and fail loudly on mismatch #897
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#897
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Every process re-loads the map by name:
Implementation#current_map(model/implementation.rb:71) andImplementation::Targeting#map(model/implementation/targeting.rb:6). If the map file is edited while a run is open,Map#noderaises on a node that no longer exists, deep inside a gate or hook. The run cannot tell that the map changed. Related to #859 (map reroute), not slice 4.Reproduce
Open an implementation, rename a node in its map YAML, call
os-sdlc-next: the error is aKeyErrorfromMap#node, not a message about the map changing.Approach
implementations.map_digestandreroutes.map_digest(nullable String) come from the #895 schema bump (29 -> 30). This ticket adds no schema change, only the behavior.implementation-open, compute the SHA-256 digest of the map file bytes that the Loader parsed (the same bytes, no separate read, to avoid a race with an edit) and store it inimplementations.map_digest. When a reroute is applied (Reroute#apply!/Landing#reroute!), store the rerouted map's digest inreroutes.map_digestthe same way.Map::Catalog#load(adapter/map/catalog.rb:23), the single choke point, rather than at each caller:loadtakes the stored digest, parses, and compares with the digest of the bytes it parsed. On mismatch it raisesMap::ChangedError(*Errorin*_error.rb, aHarnessErrorsubclass likeProject::TargetSelectionError, so model/map/changed_error.rb) whose message names the map and says the map changed since the implementation was opened and the implementation must be reopened. A NULL stored digest means no check (rows from before the bump).bin/refresh-pluginsthat ships a map edit fails every live run on that map, loudly. That is intended: ADR-0169 says map contents are frozen, ADR-0160 treats them as configuration, and this ticket enforces "frozen for the life of a run" (ADR-0261 is context).Do not add recovery, a map snapshot, an auto-reopen, a heuristic or an ENV override. Failing loudly is the whole behavior. Depends on #895 (columns) and #880 (
Map#path).Required work:
SHA256inplugins/os-sdlc/lib/os_sdlc/adapter/map/loader.rbmap_digestinplugins/os-sdlc/lib/os_sdlc/command/implementation/open.rbmap_digestinplugins/os-sdlc/lib/os_sdlc/command/implementation/landing.rbChangedErrorinplugins/os-sdlc/lib/os_sdlc/adapter/map/catalog.rbChangedErrorinplugins/os-sdlc/lib/os_sdlc/model/map/changed_error.rbAcceptance criteria
Map::ChangedErrornames the mapxand says it changed since the implementation opened.Owner sketch
No
map_digestmethod onImplementation: it would shadow the Sequel column reader.Origin
Parent: #859 (mention only; not a slice 4 blocker)
Blocked by: #895, #880
VERDICT: CREATE (ticket-skeptic 2026-10-02: user-approved; reproducible KeyError on mid-run map edit)
Store a hash of the map file on the run row at opento Store a digest of the map file on implementations at open and fail loudly on mismatchWork started on branch ticket-897 through /os-sdlc:implement (poodr-ticket-implementation, target os-sdlc).
Stale-handoff replay (implementation 6, 2026-10-02): the test-writer submitted the change-auditor's leftover scratchpad/h.json; subagent-stop replayed completed dispatch 24 and dispatch 26 stayed open. Skeptic verdict DROP: the root is the brief rule naming no file. Fix applied in briefs: each agent writes handoff-<dispatch_id>-.json and checks the reply's dispatch_id.
Resolution
Done: Map digest, option A (fail loudly only): Map::Source holds the map file path and the SHA-256 digest of its bytes. implementations.map_digest is stored at open, and reroutes.map_digest at reroute apply. Map::Catalog#load(name, digest:) raises Map::ChangedError ('reopen the implementation') when the file changed since then. No recovery and no snapshot.
Evidence: Branch ticket-897:
d93e4600(Runner commit, implementation 6, 16 dispatches, 21 min 24 s),e43b1864(adds model/map/source.rb, which the Runner commit path list omitted),f3a9943c(History row). Full os-sdlc suite on the clean tree: 1425 runs, 0 failures, 0 errors. New test: plugins/os-sdlc/tests/model/implementation_map_digest_test.rb.Follow-ups: #905 (Lens proposal: Implementation.open takes **columns, so a caller can override fixed columns; filed with skeptic VERDICT: CREATE). Stale-handoff replay during this run: skeptic DROP, reason posted on #897 and #901. The Runner commit omitted a new file created by the refactorer: noted in this close; I captured no separate ticket.