"Ship run-state manifest (ship-manifest@1) - resumable 31-step chain + depends_on-aware queue selection"
TASK-CUO-206: Ship run-state manifest
§1 - Description
Give /ship-tasks the same re-entrancy anchor its authoring sibling already has: a per-task manifest that records which of the 31 steps completed, over which artefacts, so a new session resumes instead of re-deriving - plus deterministic queue selection when no task id is given.
Normative clauses:
- A contract
ship-manifest@1MUST be defined atmodules/skill/contracts/task/SHIP-MANIFEST.mdwith fields:manifest_version(constship-manifest@1),task_id,task_sha256(hash of the task spec file at run start - a later mismatch marks the whole manifest stale),workflow_version(from the workflow doc),started_at,updated_at,current_step(1..31),routed_back_count,steps[]- each{index, skill, status (pending|done|failed|skipped-conditional), artefact_path, artefact_sha256, verdict, completed_at}- andhitl({gate: null|review_approval|final_acceptance, requested_at}). - The ship workflow MUST write the manifest to
docs/tasks/.workflow/<task-ID>.ship.jsonafter EVERY completed, failed, or conditionally-skipped step, using two-phase atomic writes (.tmp.<nonce>then rename), mirroring the memory-protocol write discipline. - On invocation for a task whose manifest exists with matching
workflow_version, ship MUST resume at the first non-done step AFTER re-verifying every recordedartefact_sha256against disk; a mismatch marks that step and all later steps stale (redo from the earliest stale step). Aworkflow_versionmismatch MUST route to needs_human, never a silent mixed-version run. - Invoked WITHOUT a task id, ship MUST select deterministically: among tasks at
ready_to_implementwhosedepends_onare alldone, order by priority (MUST before SHOULD before COULD), thencreatedascending, then id ascending; the selection and its reasoning line MUST be echoed to the operator before step 1 runs. - Manifests MUST be gitignored via a scaffolded
docs/tasks/.workflow/.gitignore(content:*.ship.json); task frontmatter and BACKLOG.md remain the only committed state./installMUST scaffold the same ignore file in target repos. - On the task reaching
done(HITL gate 2 passed), ship MUST delete the manifest; on route-back toready_to_implement, ship MUST keep it withrouted_back_countincremented (the next run starts fresh at step 1 by §1 #3's staleness rule but retains the count and history). - The workflow doc MUST gain a
## Resume semanticssection and EXECUTION-DISCIPLINE.md a pointer to it; the plugin wrapper SKILL.md MUST mention resume-on-restart so agents look for the manifest before starting step 1. - HITL gates MUST NOT be inferable from the manifest alone: resuming at a gate step re-requests the human approval; a recorded
hitl.requested_atnever substitutes for the approval itself.
§2 - Why this design
The manifest is a cache of proven work, never an authority: every resume re-hashes artefacts, and human gates always re-ask. That keeps the two-source-of-truth risk (manifest vs backlog) at zero - if the manifest lies or is deleted, the worst case is redoing work, the exact status quo. JSON-on-disk with atomic writes copies the pattern already proven by the authoring manifest; queue selection turns "pick the next eligible one" from prose into an algorithm agents apply identically across repos.
§3 - Contract
{
"manifest_version": "ship-manifest@1",
"task_id": "TASK-TEN-208",
"task_sha256": "4c1e...",
"workflow_version": "2.3.1",
"started_at": "2026-07-12T10:00:00+07:00",
"updated_at": "2026-07-12T11:42:10+07:00",
"current_step": 11,
"routed_back_count": 0,
"steps": [
{"index": 1, "skill": "repo-context-map-author", "status": "done",
"artefact_path": "docs/tasks/.workflow/TASK-TEN-208.rcm.md",
"artefact_sha256": "9f2c...", "verdict": "pass", "completed_at": "2026-07-12T10:12:00+07:00"},
{"index": 3, "skill": "architecture-decision-record-author", "status": "skipped-conditional",
"artefact_path": null, "artefact_sha256": null, "verdict": null, "completed_at": "2026-07-12T10:13:00+07:00"}
],
"hitl": {"gate": null, "requested_at": null}
}
§4 - Acceptance criteria
- Schema is normative and validated (§1 #1) - SHIP-MANIFEST.md defines every field with types/enums; the §3 example and the fixtures validate against it programmatically.
- Write-after-every-step, atomically (§1 #2) - the workflow doc mandates the write points and the tmp+rename discipline; no step's completion is unrecorded.
- Resume skips proven work (§1 #3) - fixture: manifest with steps 1-10 done and artefacts intact -> resume plan says step 11; corrupting step 5's artefact makes the resume plan restart at 5 with 5..31 stale.
- Version mismatch halts (§1 #3) - manifest at 2.3.0 vs workflow 2.3.1 -> needs_human, no auto-run.
- Queue selection is total and deterministic (§1 #4) - fixture backlog (mixed statuses, unmet depends_on, tied priorities) yields one defined winner; re-running yields the same; the reasoning line matches the fixture expectation.
- Gitignore scaffolding (§1 #5) - the ignore file exists with
*.ship.json;git statusin a fixture repo shows no manifest after a simulated run; install.sh scaffolds it in a scratch target. - Terminal handling (§1 #6) - done deletes the manifest; route-back keeps it with the incremented count (fixture pair).
- Human gates re-ask on resume (§1 #8) - resuming a manifest parked at step 19/31 (gates) produces a fresh approval request; the doc forbids treating requested_at as approval.
§5 - Verification
# modules/cuo/tests/test_ship_manifest.py
def test_schema_fields_and_example_validate(): # AC 1
def test_atomic_write_discipline_documented(): # AC 2 (workflow doc contains the write-point + tmp/rename clauses)
def test_resume_plan_intact_and_stale(): # AC 3 (pure function over fixture manifests + artefact dir)
def test_workflow_version_mismatch_needs_human(): # AC 4
def test_queue_selection_total_order(): # AC 5 (fixture task set -> expected id; idempotent)
def test_gitignore_scaffold(): # AC 6
def test_done_deletes_routeback_keeps(): # AC 7
def test_hitl_reask_on_resume(): # AC 8 (doc assertion + fixture plan marks gate pending)
(The resume planner and queue selector are specified in the workflow doc precisely enough to implement as small pure helpers under modules/cuo for testability; agents follow the same algorithm doc-driven in reduced profile.)
§6 - Implementation skeleton
SHIP-MANIFEST.md mirrors MANIFEST_SCHEMA.md's structure (field table, lifecycle, atomicity, staleness). Workflow doc: add manifest write-points to the step protocol preamble, the Resume semantics section (staleness rule, version rule, gate re-ask), and the queue algorithm where the doc currently says "next eligible task".
§7 - Dependencies
None hard. TASK-CUO-207's config later adds nothing here (manifest location is fixed). Interacts with TASK-CUO-205 only at the shared backlog-write skill, unchanged for ship. TASK-SKILL-118's coverage-gate rubric constants are read at their steps regardless of resume.
§8 - Example payloads
Resume echo line (operator-facing):
resume TASK-TEN-208: steps 1-10 verified (10 artefacts, hashes OK), continuing at step 11/31 (observability-injection-author). routed_back_count=0
§9 - Open questions
None blocking. Cross-repo parallel shipping (two agents, two different tasks, one repo) is naturally safe - one manifest per task; two agents on the SAME task is out of scope and remains an operator error the backlog's status cell already surfaces.
§10 - Failure modes inventory
- Crash between artefact write and manifest write - resume re-verifies hashes; the missing manifest entry means the step re-runs, idempotent by skill design.
- Manifest edited by hand to skip a gate - §1 #8: gates re-ask regardless of manifest content; the manifest cannot authorize anything.
- Stale manifest after task spec edits (task re-audited mid-flight) - covered by the schema's
task_sha256root field (§1 #1): mismatch at resume marks every step stale, forcing a clean re-run against the revised spec. - .workflow dir deleted - clean restart from step 1; no correctness loss (cache semantics).
- Clock skew across sessions - ordering uses step indices, not timestamps; timestamps are informational only.
§11 - Implementation notes
Keep the manifest strictly derived (cache) - the words "record of truth" appear only next to task frontmatter in every doc touched. The queue reasoning line format is part of the contract (operators grep session logs for it).
End of TASK-CUO-206.
Audit
TASK-CUO-206 audit
§1 - Verdict summary
Audited hardest on the one danger a run-state manifest introduces: becoming a second source of truth. The revised spec keeps it strictly a cache (hash-verified on resume, gates always re-ask, deletable at zero correctness cost). Queue selection moved from prose to a total order. Traceability closes over the eight tests in modules/cuo/tests/test_ship_manifest.py (in new_files).
§2 - Findings (all resolved)
ISS-001 two-sources-of-truth risk
A trusted manifest could contradict the backlog. Resolved: cache-only doctrine (§2), resume re-verifies every artefact hash (§1 #3), HITL gates re-ask regardless of manifest content (§1 #8, AC 8), and deletion is always safe (§10 #4).
ISS-002 task spec edits mid-flight were invisible
Steps proven against version N of the spec would resume against version N+1. Resolved: task_sha256 root field in the schema (§1 #1) with all-stale semantics; §3 example updated; §10 #3 cites the field instead of deferring it.
ISS-003 mixed-workflow-version resume
2.3.0 manifest under a 2.3.1 workflow silently blends step semantics. Resolved: §1 #3 needs_human on version mismatch, AC 4.
ISS-004 queue selection had undefined ties
"Next eligible" without a total order produces different picks per agent. Resolved: §1 #4 priority -> created -> id ordering with an operator-visible reasoning line, AC 5 determinism assertion.
ISS-005 committed-or-ignored ambiguity
Manifests in git would churn every ship run; unstated either way invites both. Resolved: §1 #5 gitignore scaffold (repo + install.sh), AC 6.
ISS-006 terminal-state handling
Manifests of done tasks would accumulate; route-backs would lose history. Resolved: §1 #6 delete-on-done, keep-with-incremented-count on route-back, AC 7 fixture pair.
§3 - Resolution
All six findings addressed as cited. The task upgrades ship from restartable to resumable without moving any authority off task frontmatter. Score = 10/10.
End of TASK-CUO-206 audit.
§10 - Ship record (2026-07-12)
- §10.1 Implementation: contract + helpers + tests + workflow v2.4.0 Resume semantics + scaffolds, commit f06ff65 (rebased onto PR #44 version-reset mid-flight; original hash 46911d8 superseded); phase artefacts at docs/tasks/.workflow/TASK-CUO-206/.
- §10.2 Review: clause-by-clause pass (packet in phase-bundle); human verdict at gate 1: APPROVE + pre-authorize done (Stephen Cheng, in-chat).
- §10.3 Testing: 8/8 AC tests, 100.0% statement coverage on modules/cuo/cuo/ship_manifest.py (raised from 77.3% by covering validate error branches + write_atomic failure cleanup), 5/5 cyberos-install suites, git check-ignore proof. Gate 2 recorded per pre-authorization.
- §10.4 Field finding folded back: TASK-CUO-209 t08 temporal-scope guard amended to durable workflows_vendored_intact (TASK-CUO-209 §1 #8, AC 8, audit §11).
Verdict unchanged: PASS, Score = 10/10.