| name | backlog-state-update-author |
| description | Write `docs/tasks/BACKLOG.md` mutations as backlog-state-update@2: rewrite one status cell atomically (used by `chief-technology-officer/ship-tasks` between every phase; the same write emits the `workflow_complete` memory row), or INSERT one new row (`mutation_kind: insert-row` - /create-tasks step 3; regenerator-identical grammar, uniqueness-gated). Statuses constrained to the 10-value enum in `modules/skill/contracts/task/STATUS-REFERENCE.md` §1; failures route the task back to `ready_to_implement` (§1.3) incrementing `routed_back_count`. Use when user asks to "draft a backlog state update" or "create the backlog state update". Do NOT use for "audit existing backlog state update" (use backlog-state-update-audit instead). HITL note - operators can override any cell at any time; this skill writes only the default workflow-driven transition (§1.4). |
| license | Apache-2.0 |
| metadata | {"version":"2.1.0","module":"skill","stage":"e","cyberos-template":"backlog-state-update@2","cyberos-rubric-target":"backlog_state_update_rubric@1.0"} |
| allowed_memory_scopes | {"read":["project:*"],"write":["project:task/{task_id}/backlog-state-update","project:backlog/{task_id}"]} |
| audit | {"row_kind":"backlog_state_update_authored","required_fields":["task_id","prior_status","new_status","line_number","evidence_artefact_ids"]} |
| inputs | [{"name":"task","format":"task@1","required":true},{"name":"outcome","format":"workflow-step-outcome-bundle@1","required":true}] |
| outputs | [{"name":"backlog_mutation","format":"backlog-state-update@2"}] |
| triggers | [{"workflow `chief-technology-officer/ship-tasks` — invoked between every phase transition (mutation_kind":"status-cell-only)"},"command `/create-tasks` step 3 — one insert-row mutation per landed task (batched per module section allowed)"] |
| blockers | ["BACKLOG.md is locked by another concurrent workflow — wait for lock","BACKLOG.md has divergent uncommitted changes — escalate to operator"] |
| untrusted_inputs | {"wrap_in_marker":"untrusted_content","injection_scan":"required","on_marker_hit":"surface_to_human"} |
backlog-state-update-author
1. Purpose
The BACKLOG is the single source of truth for task state. This skill is the only authorised writer; every other step in the workflow emits artefacts, but this is the step that flips the status cell. The mutation is atomic with the workflow_complete memory row, so the chain and the state file can never disagree.
This skill is called between every phase transition of ship-tasks, not just on terminal outcomes:
ready_to_implement → implementing (workflow start)
implementing → ready_to_review (build complete)
ready_to_review → reviewing (reviewer claims)
reviewing → ready_to_test (review approved)
ready_to_test → testing (tester claims)
testing → done (coverage-gate-audit passes) Declared mutation footprint (TASK-IMP-116). A backlog-state-update@2 write declares THREE lines: the status cell's row, its section header (retallied from the section's rows; a BARE header carries no counts and stays untouched), and the file-top Totals: line (retallied from every row in the file). Capped at three - a footprint that grows on convenience is not a footprint.
TASK-IMP-092 replaced incremental header adjustment with a retally because "incremental adjustment faithfully preserves an inherited lie forever (the 086 incident's 34 vs true 20)". It stopped at section headers, and the file's most-read number rotted exactly as that argument predicts: a 2026-07-17 review found Totals: 336 draft, 4 ready_to_implement, 176 done over a file whose improvement section alone read 67/9/39. regen_backlog owns that line and cannot run. Every mutation now emits the whole file's truth, not just its section's.
Footprint shapes, all deliberate: counted header -> 3 lines; bare header -> 2 (row + Totals); insert -> 1 added row + 2 changed lines. A file with no Totals: line is legal and is never given one.
- any-stage →
ready_to_implement (failure/blocker rework path, increments routed_back_count, sets entered_via: rework)
- any-stage →
draft (SPEC-rejected path, TASK-IMP-108 §1.5: increments routed_back_count, sets entered_via: spec_rejected). Use when the failure is the spec, not the code - re-authoring and re-auditing is the remedy, and would hand an unchanged wrong spec back to an implementer.