Replace reroutes.draft with applied_at (schema 30) and scope Draft#replace_draft! to its own dispatch #895
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#895
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
ADR-0261 decision 3 replaces the
reroutes.draftboolean withapplied_at(nil = pending).Reroute::Draftwrites the row when map-router proposes andLanding#reroute!applies it later; a pending row that never lands must stay distinguishable, andcreated_atdoes not record the landing. Separately,Reroute::Draft#replace_draft!(reroute/draft.rb) runsimplementation.reroutes_dataset.drafts.delete, which deletes every pending row of the implementation. ADR-0260 decision 3 says one row per dispatch, so it must delete only the rows of the same dispatch. Note: the row'sdispatch_idis the REQUESTING dispatch (@dispatch.received_handoff&.creating_dispatch), not the map-router dispatch, so "same dispatch" isdispatch_id: requester&.id(nil for the orchestrator path).Implementation#draft_reroute_forfinds the row bycreated_at >= dispatch.created_at.Reproduce
In a test, add a pending row for requester dispatch A, then run
Reroute::Draft#writefor a map-router dispatch whose requester is B: the row for A is deleted today.Approach
t.TrueClass :draft ...(line 205) witht.DateTime :applied_at(nullable). Bump SCHEMA_VERSION 29 -> 30. No backfill (a stale DB is archived and recreated; reroutes is empty).applied = exclude(applied_at: nil);pending = where(applied_at: nil)(rename ofdrafts);apply!isupdate(applied_at: Time.now);to_reportreplacesdraft:withapplied_at(presenter/implementation/summary.rb:50 renders every row, so droppingdraft:without a replacement loses pending vs applied).drafts: model/implementation.rb:77 (draft_reroute_for), command/implementation/landing.rb, query/reroute/check.rb.Reroute::Draft#writestops passingdraft: true.replace_draft!: delete only pending rows whosedispatch_idequalsrequester&.id.draft:.add_reroute) must passapplied_at: Time.nowwhen it builds an applied row. The old defaultdraft: falsemeant applied; the new default nil means pending, so tests/model/implementation_current_map_test.rb, tests/command/implementation/transition_test.rb and tests/controller/implementation/change_auditor_reroute_test.rb would silently test pending rows.refute row[:draft], line 154draft: false, and the test names and message text that say "draft" (lines 25, 35, 89, 97, 101). tests/presenter/implementation/summary_reroutes_test.rb: lines 15 and 17.Implementation#draft_reroute_for(model/implementation.rb:76-77) topending_reroute_forand its callers: command/implementation/landing.rb (draftat lines 56, 60, 63) and query/reroute/check.rb (line 11,missing_draft_line, and the message "no draft reroute recorded" at line 19, which becomes "no pending reroute recorded"). agents/map-router.md lines 15 and 36 say "draft reroute": change to "pending reroute".implementations.map_pathtomap_name(adapter/db.rb:336,add_implementation_binding_columns). The column holds a map NAME, not a path. Do not add amap_namemethod or any new class on Implementation: Sequel gives the column reader. Callers that need the Map use the existingImplementation#map(model/implementation/targeting.rb:6,Map::Catalog.default.load(map_path), which becomesload(map_name)), and where they need the name,map.name(duck typing).Map::Catalogkeeps its name (ADR-0262). Column readers and writers ofmap_pathfound in plugins/os-sdlc: model/implementation.rb:56 (create(... map_path: work_order.map_path ...)becomesmap_name:), model/implementation/targeting.rb:6, tests/command/implementation/open_map_name_test.rb:22 (row[:map_path]), tests/model/implementation_current_map_test.rb:22 (reloaded.map_path), and the directimplementationsinserts orImplementation.createcalls withmap_path: "map.yml"in tests/model/handoff_test.rb:11 and :80, tests/model/correction_round_test.rb:10 and :86, tests/model/step_result_test.rb:111, tests/model/inverse_associations_test.rb:8, tests/model/implementation/landing/escalation_reason_test.rb:42, tests/command/gate/run_classification_test.rb:35. Not the column, so they may keep their own name: the CLI-side work-order fieldDispatch::WorkOrder#map_path(model/dispatch/work_order.rb:5-6),ArgsHolder#map_path!and its use inwork_order_fields!(parser/dispatch_commands/args_holder.rb:28,38),command/implementation/open.rb:18, and the roughly 80WorkOrder.new(... map_path: ...)calls in tests. Do not rename them in this ticket; the CLI positional argument is a map name too, so renaming that field tomap_nameis a separate follow-up.map_digestString column toimplementationsand toreroutesin the same schema bump (for #897, which adds only the behavior: store, compare, raise). Do not add amap_digestmethod on Implementation or Reroute: Sequel gives the column reader.bin/refresh-plugins.Do not bump the schema while a run is live (ADR-0129, ADR-0155); #880 (implementation 14) must be abandoned or finished first.
Required work:
applied_atinplugins/os-sdlc/lib/os_sdlc/adapter/db.rbSCHEMA_VERSION = 30inplugins/os-sdlc/lib/os_sdlc/adapter/db.rbdraft:inplugins/os-sdlc/lib/os_sdlc/model/reroute.rbdispatch_idinplugins/os-sdlc/lib/os_sdlc/reroute/draft.rbapplied_atin the reroute report — check: presentapplied_at: applied_atinplugins/os-sdlc/lib/os_sdlc/model/reroute.rbapplied_at— check: presentapplied_atinplugins/os-sdlc/tests/support/reroute_test_case.rbdraftinplugins/os-sdlc/tests/controller/implementation/map_update_test.rbdraftinplugins/os-sdlc/tests/presenter/implementation/summary_reroutes_test.rbdraft_reroute_forinplugins/os-sdlc/lib/**/*.rbdraft rerouteinplugins/os-sdlc/agents/map-router.mdmap_name— check: absentmap_pathinplugins/os-sdlc/lib/os_sdlc/adapter/db.rbmap_digestinplugins/os-sdlc/lib/os_sdlc/adapter/db.rbbin/refresh-plugins) — check: present#895indocs/implementation-status/os-sdlc.mdAcceptance criteria
applied_atnil, whenReroute.pendingandReroute.appliedare read, then the row is in pending only.apply!runs, thenapplied_atis set and the row is inappliedonly;current_mapand the cap count it.Reroute::Draft#writeruns, then A's row remains and B's new row is added.writeruns a second time for the same requester, then one pending row for B remains.rerouteshasapplied_atand nodraftcolumn.to_reportruns on each, then the report hasapplied_at(a time for the applied row, nil for the pending row) and nodraftkey, and the run summary shows it.implementationsis read, then it has amap_namecolumn and nomap_pathcolumn.implementationsandreroutesare read, then each has a nullablemap_digestcolumn.Owner sketch
Origin
Parent: #859
Blocked by: #899
VERDICT: CREATE (ticket-skeptic 2026-10-02: user-directed ADR-0261 ruling; fixes replace_draft! scope defect)
jared referenced this issue2026-10-02 12:45:07 +00:00
Work started: /os-sdlc:implement on branch ticket-895 (worktree .claude/worktrees/ticket-895). Implementation 14 was abandoned through #899, so the schema bump is allowed.
Resolution
Done: Schema 30: reroutes.draft replaced by nullable applied_at (pending = nil; applied/pending scopes; apply! stamps the time; to_report emits applied_at); replace_draft! scoped to the requester dispatch; draft_reroute_for renamed pending_reroute_for; implementations.map_path column renamed map_name; nullable map_digest on implementations and reroutes; map-router.md says pending reroute.
Evidence: Commit
bd16ce63on ticket-895 (implementation 16 complete, 12 dispatches, test-reviewer pass after 2 rounds, contract-auditor pass first time); suite-check green; new tests tests/adapter/db_schema_30_test.rb, tests/model/reroute_applied_at_test.rb, tests/reroute/draft_test.rb; History row in docs/implementation-status/os-sdlc.md.Follow-ups: WorkOrder#map_path rename captured as #900 (user-directed). Map digest behavior is #897. Pipeline DB moves to schema 30 on first connect from main after merge.