# TC Lifecycle and State Machine A TC moves through six implementation states. Transitions are validated on every write — invalid moves are rejected with a clear error. ## State Diagram ``` +-----------+ | planned | +-----------+ | ^ v | +-------------+ +-----> | in_progress | <-----+ | +-------------+ | | | | | v | v | +---------+ | +-------------+ | | blocked |<---+ | implemented | | +---------+ +-------------+ | | | | v v | +---------+ +--------+ | | planned | | tested |-----+ +---------+ +--------+ | v +----------+ | deployed | +----------+ | v in_progress (rework / hotfix) ``` ## Transition Table | From | Allowed Transitions | |------|---------------------| | `planned` | `in_progress`, `blocked` | | `in_progress` | `blocked`, `implemented` | | `blocked` | `in_progress`, `planned` | | `implemented` | `tested`, `in_progress` | | `tested` | `deployed`, `in_progress` | | `deployed` | `in_progress` | Same-status transitions are no-ops and always allowed. Anything else is an error. ## State Definitions | State | Meaning | Required Before Moving Forward | |-------|---------|--------------------------------| | `planned` | TC has been created with description and motivation | Decide implementation approach | | `in_progress` | Active development | Code changes captured in `files_affected` | | `blocked` | Cannot proceed (dependency, decision needed) | At least one entry in `handoff.blockers` | | `implemented` | Code complete, awaiting tests | All target files in `files_affected` | | `tested` | Test cases executed, results recorded | At least one `test_case` with status `pass` (or explicit `skip` with rationale) | | `deployed` | Approved and shipped | `approval.approved=true` with `approved_by` and `approved_date` | ## Recovery Flows ### "I committed before testing" 1. Status is `implemented`. 2. Write tests, run them, set `test_cases[*].status = pass`. 3. Transition `implemented -> tested`. ### "Production bug in a deployed TC" 1. Open the deployed TC. 2. Transition `deployed -> in_progress`. 3. Add a new revision summarizing the rework. 4. Walk forward through `implemented -> tested -> deployed` again. ### "Blocked, then unblocked" 1. From `in_progress`, transition to `blocked`. Add blockers to `handoff.blockers`. 2. When unblocked, transition `blocked -> in_progress` and clear/move blockers to `notes`. ### "Cancelled work" There is no `cancelled` state. If a TC is abandoned: 1. Add a final revision: "Cancelled — reason: ...". 2. Move to `blocked`. 3. Add a `[CANCELLED]` tag. 4. Leave the record in place — never delete it (history is append-only). ## Status Field Discipline - Update `status` ONLY through `tc_update.py --set-status`. Never edit JSON by hand. - Every status change creates a new revision entry with `field` = `status`, `action` = `changed`, and `reason` populated. - The registry's `statistics.by_status` is recomputed on every write. ## Anti-patterns | Anti-pattern | Why it's wrong | |--------------|----------------| | Skipping `tested` and going straight to `deployed` | Bypasses validation; misleads downstream consumers | | Deleting a record to "cancel" a TC | History is append-only; deletion breaks the audit trail | | Re-using a TC ID after deletion | Sequential numbering must be preserved | | Changing status without a `--reason` | Future maintainers cannot reconstruct intent | | Long-lived `in_progress` TCs (weeks+) | Either too big — split into sub-TCs — or stalled and should be marked `blocked` |