Spec: os-backlog issue lifecycle implementation (from map #239) #250

Closed
opened 2026-08-04 11:28:33 +00:00 by jared · 1 comment
Owner

Spec generated from wayfinder map #239 (os-backlog issue lifecycle & templates); revised 2026-08-04 after a Codex second-opinion review (14 findings; accepted defects and clarifications folded in below and into the design doc). Design source of truth: docs/os-backlog-lifecycle.md + ADR-0092..0096, merged to main (ea9d019). This issue is the spec parent — the work rides on its child implementation tickets (Spec: #250 in each body), per the design's own one-agent-session ticket standard.

Problem Statement

As a solo freelancer running an always-on backlog across projects, I have no decided, enforced lifecycle for issues. Captures, tickets, and maps are informal; templates live inside os-sdlc where other consumers can't reach them; "ready-for-agent" is an honesty-system label with no machine check; agents close issues without a consistent evidence trail; and wayfinder decomposition uses conventions os-backlog knows nothing about. The result is lifecycle leaks: under-specified tickets picked up by agents, follow-ups lost at close time, and no structural way to tell what state an issue is actually in.

Solution

Implement the decided os-backlog lifecycle: capture → refine → check-out → work → close. Canonical spec/ticket/capture templates move into os-backlog. A deterministic Ruby template validator computes an issue's structural tier (capture/ticket/map) and gates the self-applied ready-for-agent label at refine-exit and again at pickup. Decision children carry fenced-YAML weighted-recommendation blocks; a recommender-blind Ruby sweep CLI (bin/decision-sweep) auto-closes cheap-reversal recommendations at ≥85% confidence and routes the rest to a human. Every AI close carries a three-part resolution comment. Wayfinder's map conventions are documented in os-backlog and its issues are exempt from readiness sweeps.

User Stories

  1. As a backlog owner, I want to capture an idea with just a title and two lines of context, so that intake stays friction-free and nothing is lost mid-session.
  2. As a backlog owner, I want captures to be a legitimate permanent resting state, so that I'm never nagged to refine work I haven't chosen to do.
  3. As a working agent, I want an issue's tier (capture/ticket/map) computed from its structure rather than asserted by labels, so that labels can't lie about readiness.
  4. As a refining agent, I want a standing checklist (fill template, adr-find, link issues, spawn decision children, apply readiness labels), so that refinement is consistent and end-to-end without a human gate in the hot path.
  5. As a refining agent, I want to self-apply ready-for-agent only after the template validator passes and all decision children are closed, so that the label is a machine-backed claim.
  6. As a refining agent, I want to close objectively-verifiable duplicate/already-done captures with evidence, so that the backlog doesn't accumulate dead items.
  7. As a refining agent, I want to flag "needs a map" and bounce to the human rather than charting, so that map charting stays human-in-the-loop.
  8. As a recommending agent, I want to end each decision child with a fenced YAML block (recommendation, confidence, reversal_cost, reasoning), so that my recommendation is machine-parseable below the prose memo.
  9. As a backlog owner, I want the sweep threshold hardcoded in a tested Ruby CLI the recommender never loads, so that recommender-blindness holds structurally, not by convention.
  10. As a backlog owner, I want the sweep to auto-close children whose recommendation clears ≥85% confidence with cheap reversal, so that low-risk decisions don't wait on me.
  11. As a backlog owner, I want sweep failures commented with the failed gate and labelled ready-for-human, so that only genuinely contested decisions reach me.
  12. As a working agent, I want claiming to be assignee + start comment universally, so that concurrent sessions skip claimed tickets deterministically.
  13. As a working agent, I want a staleness + falsifiability checkpoint at ready-for-agent pickup (rerun validator, verify paths/ADRs/children, cold-read for clarifying questions), so that stale tickets bounce to refine instead of producing wrong work.
  14. As a working agent, I want a fixed context-load (ticket + spec + linked ADRs + decision-children resolutions), so that pickup context is predictable and bounded.
  15. As a backlog owner, I want every AI close to carry a three-part resolution comment (done / evidence links / follow-ups captured-or-dropped), so that lifecycle leaks are caught at the close boundary.
  16. As a backlog owner, I want pipeline-worked tickets to close at merge with approval subsuming the review label, so that there's no duplicate sign-off step.
  17. As a backlog owner, I want recurring issues to record occurrence outcomes with the same comment shape without closing, so that recurring work keeps its history.
  18. As an os-sdlc user, I want spec/ticket templates canonical in os-backlog with os-sdlc linking to them, so that one source serves every consumer and the dependency direction (ADR-0037) holds.
  19. As a capture-skill user, I want /os-backlog:capture to emit the minimal capture template, so that captures are structurally recognizable to the validator.
  20. As a wayfinder user, I want wayfinder:map/wayfinder:<type> labels, Map: #NNN, and Blocked by #NNN documented in os-backlog references, so that there's one vocabulary, not two.
  21. As list/loop tooling, I want wayfinder:* issues skipped in readiness sweeps, so that map children (whose type label encodes routing) aren't flagged as unlabeled limbo.
  22. As a developer, I want the validator and sweep sharing one Ruby CLI/lib surface with the deterministic ticket-filing CLI (#186), so that tracker access and body parsing are implemented once.

Implementation Decisions

  • Three structural tiers, computed never asserted (ADR-0092): wayfinder:map label ⇒ map; required template sections present ⇒ ticket; otherwise capture. Recurring/cross-project/wayfinder-child are flavors on a tier.
  • Canonical templates (spec, ticket, capture) live in os-backlog's references, promoted from os-sdlc's spec-and-ticket layer; os-sdlc links, never inlines (ADR-0093). Capture template is title + ## Context.
  • Refine is an enhancement of the installed triage skill: auto-triggered at pick-up when ticket-tier structure is missing, standalone-invocable for grooming. Checklist: template fill (3–7 given/when/then acceptance criteria, non-goals), /os-adr:find on touched paths, issue linking, decision children, readiness labels.
  • Weighted-decision block (ADR-0094): fenced YAML with recommendation, confidence (integer %), reversal_cost (cheap|moderate|expensive), reasoning (one line), below the prose memo. Sweep CLI holds the gate (≥85% AND cheap) hardcoded; pass ⇒ adopt + close with three-part comment; fail (any gate, or malformed/missing block) ⇒ named-gate comment + ready-for-human. This ready-for-human is the sweep's routing verdict, not a readiness-tier claim: it applies even to wayfinder:* children, which readiness sweeps still skip (the one exception to the wayfinder exemption — ADR-0096, amended).
  • Decision-child linkage grammar: refine appends a Blocked by #NNN line to the parent ticket's body per child; "all decision children closed" is computed from those lines; an unfetchable reference is a validation failure, never silently skipped.
  • Mutation ordering: every multi-step tracker sequence posts its comment first, then labels/closes; re-running after a partial failure is idempotent (existing comment detected, remaining steps applied).
  • Template validator (ADR-0095): deterministic Ruby, computes tier and diffs sections against canonical templates; runs at refine-exit (gates ready-for-agent) and pickup; never at capture. Normative section semantics: present iff the ## heading exactly matches the template (case-sensitive, any order) and the body is non-empty after stripping HTML comments/placeholders; duplicate headings and wrong depth are malformed; the test fixtures are the authority for accepted/rejected forms.
  • Check-out: claim = assignee + start comment; checkpoint on ready-for-agent pickups only; any clarifying question strips the label with a comment and bounces. Post-bounce state: assignee removed, ready-for-agent stripped, one bounce comment naming the question; re-bounce is idempotent. Link grammar for context-load: Spec: #NN key case-insensitive at line start, at most one; a dead/unfetchable link is a checkpoint failure ⇒ bounce.
  • Label invariant: ready-for-agent and ready-for-human are mutually exclusive; tooling finding both strips ready-for-agent with a comment and keeps ready-for-human.
  • Close: three-part ## Resolution comment mandatory on AI closes, enforced at the os-backlog surface — the close command/skill refuses without a valid resolution comment; direct-API closes are out of protocol, not policed by code. Human closes encouraged, not policed. Merge approval subsumes review for pipeline-worked tickets, recognized mechanically by a PR/branch link in the start or resolution comment. Recurring issues carry a recurring label as the flavor's mechanical marker.
  • Wayfinder integration (ADR-0096): conventions adopted as-is; map spawn is flag + human charts; assembly ticket created at charting, agent-maintained; wayfinder:<type> supersedes readiness labels.
  • Shared CLI surface: validator and decision-sweep share one Ruby lib in os-backlog (tracker fetch, body/section parsing, label ops). That lib implements #186's deterministic ticket-filing surface — #186 closes when it lands, it is not separate work. Ruby + Sandi Metz OOP style; gate logic in code, not prompts.
  • Skill and reference-doc changes follow os-backlog's existing SKILL.md structure and the cc-os naming conventions; run bin/refresh-plugins after plugin edits.

Testing Decisions

  • One seam: the os-backlog Ruby CLI/lib boundary, tested with minitest. Fixture issue bodies (markdown strings/files) + a stubbed tracker fetch; assertions on exit status, emitted output, and requested tracker mutations. No live tracker in tests.
  • Test external behavior only: "given this body, tier is X / validation reports Y", "given this decision child, sweep closes/routes" — never internal parser structure.
  • Prior art: os-adr's CLI tests (plugins/os-adr/) and os-aidd-lint's Tier 1 cop tests; the actor/evaluator split mirrors os-aidd-lint's charter-judge.
  • Skill/prompt artifacts (capture, refine, check-out, close, wayfinder docs) have no code seam: verified by os-aidd-lint and production session audits, not tests.

Out of Scope

  • Executing os-sdlc pipeline changes beyond relinking the spec-and-ticket layer to the canonical templates.
  • Client-channel intake (external request → autonomous worktree → review) — a future map.
  • The nine candidate backlog operations from the #245 inventory (triage sweep, stale grooming, duplicate detection, etc.) — ticketing input, not lifecycle-blocking.
  • Auto-charting maps, or any agent-driven map work; maps stay HITL.
  • Herdr-cli pane/worktree orchestration for the eventual autonomous loop.

Further Notes

  • The design (ADR-0092..0096 + docs/os-backlog-lifecycle.md) is merged to main; implementation is unblocked.
  • The work is ticketed as child issues carrying Spec: #250, sequenced by Blocked by #NNN lines: templates → capture/validator(+shared lib) → sweep → refine/check-out, with close-protocol and wayfinder-docs unblocked from the start.
  • Declined review findings (recorded deliberately, per no-speculative-hardening): atomic compare-and-claim, revision-precondition label mutations, adapter contract tests with recorded payloads, live-tracker integration tests — single-user tracker; assignee check + cheap reversal + comment-first idempotency cover the realistic failures.
_Spec generated from wayfinder map #239 (os-backlog issue lifecycle & templates); revised 2026-08-04 after a Codex second-opinion review (14 findings; accepted defects and clarifications folded in below and into the design doc). Design source of truth: `docs/os-backlog-lifecycle.md` + ADR-0092..0096, **merged to main** (ea9d019). This issue is the spec parent — the work rides on its child implementation tickets (`Spec: #250` in each body), per the design's own one-agent-session ticket standard._ ## Problem Statement As a solo freelancer running an always-on backlog across projects, I have no decided, enforced lifecycle for issues. Captures, tickets, and maps are informal; templates live inside os-sdlc where other consumers can't reach them; "ready-for-agent" is an honesty-system label with no machine check; agents close issues without a consistent evidence trail; and wayfinder decomposition uses conventions os-backlog knows nothing about. The result is lifecycle leaks: under-specified tickets picked up by agents, follow-ups lost at close time, and no structural way to tell what state an issue is actually in. ## Solution Implement the decided os-backlog lifecycle: capture → refine → check-out → work → close. Canonical spec/ticket/capture templates move into os-backlog. A deterministic Ruby template validator computes an issue's structural tier (capture/ticket/map) and gates the self-applied `ready-for-agent` label at refine-exit and again at pickup. Decision children carry fenced-YAML weighted-recommendation blocks; a recommender-blind Ruby sweep CLI (`bin/decision-sweep`) auto-closes cheap-reversal recommendations at ≥85% confidence and routes the rest to a human. Every AI close carries a three-part resolution comment. Wayfinder's map conventions are documented in os-backlog and its issues are exempt from readiness sweeps. ## User Stories 1. As a backlog owner, I want to capture an idea with just a title and two lines of context, so that intake stays friction-free and nothing is lost mid-session. 2. As a backlog owner, I want captures to be a legitimate permanent resting state, so that I'm never nagged to refine work I haven't chosen to do. 3. As a working agent, I want an issue's tier (capture/ticket/map) computed from its structure rather than asserted by labels, so that labels can't lie about readiness. 4. As a refining agent, I want a standing checklist (fill template, adr-find, link issues, spawn decision children, apply readiness labels), so that refinement is consistent and end-to-end without a human gate in the hot path. 5. As a refining agent, I want to self-apply `ready-for-agent` only after the template validator passes and all decision children are closed, so that the label is a machine-backed claim. 6. As a refining agent, I want to close objectively-verifiable duplicate/already-done captures with evidence, so that the backlog doesn't accumulate dead items. 7. As a refining agent, I want to flag "needs a map" and bounce to the human rather than charting, so that map charting stays human-in-the-loop. 8. As a recommending agent, I want to end each decision child with a fenced YAML block (recommendation, confidence, reversal_cost, reasoning), so that my recommendation is machine-parseable below the prose memo. 9. As a backlog owner, I want the sweep threshold hardcoded in a tested Ruby CLI the recommender never loads, so that recommender-blindness holds structurally, not by convention. 10. As a backlog owner, I want the sweep to auto-close children whose recommendation clears ≥85% confidence with cheap reversal, so that low-risk decisions don't wait on me. 11. As a backlog owner, I want sweep failures commented with the failed gate and labelled `ready-for-human`, so that only genuinely contested decisions reach me. 12. As a working agent, I want claiming to be assignee + start comment universally, so that concurrent sessions skip claimed tickets deterministically. 13. As a working agent, I want a staleness + falsifiability checkpoint at `ready-for-agent` pickup (rerun validator, verify paths/ADRs/children, cold-read for clarifying questions), so that stale tickets bounce to refine instead of producing wrong work. 14. As a working agent, I want a fixed context-load (ticket + spec + linked ADRs + decision-children resolutions), so that pickup context is predictable and bounded. 15. As a backlog owner, I want every AI close to carry a three-part resolution comment (done / evidence links / follow-ups captured-or-dropped), so that lifecycle leaks are caught at the close boundary. 16. As a backlog owner, I want pipeline-worked tickets to close at merge with approval subsuming the `review` label, so that there's no duplicate sign-off step. 17. As a backlog owner, I want recurring issues to record occurrence outcomes with the same comment shape without closing, so that recurring work keeps its history. 18. As an os-sdlc user, I want spec/ticket templates canonical in os-backlog with os-sdlc linking to them, so that one source serves every consumer and the dependency direction (ADR-0037) holds. 19. As a capture-skill user, I want `/os-backlog:capture` to emit the minimal capture template, so that captures are structurally recognizable to the validator. 20. As a wayfinder user, I want `wayfinder:map`/`wayfinder:<type>` labels, `Map: #NNN`, and `Blocked by #NNN` documented in os-backlog references, so that there's one vocabulary, not two. 21. As list/loop tooling, I want `wayfinder:*` issues skipped in readiness sweeps, so that map children (whose type label encodes routing) aren't flagged as unlabeled limbo. 22. As a developer, I want the validator and sweep sharing one Ruby CLI/lib surface with the deterministic ticket-filing CLI (#186), so that tracker access and body parsing are implemented once. ## Implementation Decisions - **Three structural tiers, computed never asserted** (ADR-0092): `wayfinder:map` label ⇒ map; required template sections present ⇒ ticket; otherwise capture. Recurring/cross-project/wayfinder-child are flavors on a tier. - **Canonical templates** (`spec`, `ticket`, `capture`) live in os-backlog's references, promoted from os-sdlc's spec-and-ticket layer; os-sdlc links, never inlines (ADR-0093). Capture template is title + `## Context`. - **Refine** is an enhancement of the installed triage skill: auto-triggered at pick-up when ticket-tier structure is missing, standalone-invocable for grooming. Checklist: template fill (3–7 given/when/then acceptance criteria, non-goals), `/os-adr:find` on touched paths, issue linking, decision children, readiness labels. - **Weighted-decision block** (ADR-0094): fenced YAML with `recommendation`, `confidence` (integer %), `reversal_cost` (cheap|moderate|expensive), `reasoning` (one line), below the prose memo. Sweep CLI holds the gate (≥85% AND cheap) hardcoded; pass ⇒ adopt + close with three-part comment; fail (any gate, or malformed/missing block) ⇒ named-gate comment + `ready-for-human`. This `ready-for-human` is the sweep's routing verdict, not a readiness-tier claim: it applies even to `wayfinder:*` children, which readiness sweeps still skip (the one exception to the wayfinder exemption — ADR-0096, amended). - **Decision-child linkage grammar**: refine appends a `Blocked by #NNN` line to the parent ticket's body per child; "all decision children closed" is computed from those lines; an unfetchable reference is a validation failure, never silently skipped. - **Mutation ordering**: every multi-step tracker sequence posts its comment first, then labels/closes; re-running after a partial failure is idempotent (existing comment detected, remaining steps applied). - **Template validator** (ADR-0095): deterministic Ruby, computes tier and diffs sections against canonical templates; runs at refine-exit (gates `ready-for-agent`) and pickup; never at capture. Normative section semantics: present iff the `##` heading exactly matches the template (case-sensitive, any order) and the body is non-empty after stripping HTML comments/placeholders; duplicate headings and wrong depth are malformed; the test fixtures are the authority for accepted/rejected forms. - **Check-out**: claim = assignee + start comment; checkpoint on `ready-for-agent` pickups only; any clarifying question strips the label with a comment and bounces. Post-bounce state: assignee removed, `ready-for-agent` stripped, one bounce comment naming the question; re-bounce is idempotent. Link grammar for context-load: `Spec: #NN` key case-insensitive at line start, at most one; a dead/unfetchable link is a checkpoint failure ⇒ bounce. - **Label invariant**: `ready-for-agent` and `ready-for-human` are mutually exclusive; tooling finding both strips `ready-for-agent` with a comment and keeps `ready-for-human`. - **Close**: three-part `## Resolution` comment mandatory on AI closes, enforced at the os-backlog surface — the close command/skill refuses without a valid resolution comment; direct-API closes are out of protocol, not policed by code. Human closes encouraged, not policed. Merge approval subsumes `review` for pipeline-worked tickets, recognized mechanically by a PR/branch link in the start or resolution comment. Recurring issues carry a `recurring` label as the flavor's mechanical marker. - **Wayfinder integration** (ADR-0096): conventions adopted as-is; map spawn is flag + human charts; assembly ticket created at charting, agent-maintained; `wayfinder:<type>` supersedes readiness labels. - **Shared CLI surface**: validator and decision-sweep share one Ruby lib in os-backlog (tracker fetch, body/section parsing, label ops). That lib *implements* #186's deterministic ticket-filing surface — #186 closes when it lands, it is not separate work. Ruby + Sandi Metz OOP style; gate logic in code, not prompts. - Skill and reference-doc changes follow os-backlog's existing SKILL.md structure and the cc-os naming conventions; run `bin/refresh-plugins` after plugin edits. ## Testing Decisions - One seam: the os-backlog Ruby CLI/lib boundary, tested with minitest. Fixture issue bodies (markdown strings/files) + a stubbed tracker fetch; assertions on exit status, emitted output, and requested tracker mutations. No live tracker in tests. - Test external behavior only: "given this body, tier is X / validation reports Y", "given this decision child, sweep closes/routes" — never internal parser structure. - Prior art: os-adr's CLI tests (`plugins/os-adr/`) and os-aidd-lint's Tier 1 cop tests; the actor/evaluator split mirrors os-aidd-lint's charter-judge. - Skill/prompt artifacts (capture, refine, check-out, close, wayfinder docs) have no code seam: verified by os-aidd-lint and production session audits, not tests. ## Out of Scope - Executing os-sdlc pipeline changes beyond relinking the spec-and-ticket layer to the canonical templates. - Client-channel intake (external request → autonomous worktree → review) — a future map. - The nine candidate backlog operations from the #245 inventory (triage sweep, stale grooming, duplicate detection, etc.) — ticketing input, not lifecycle-blocking. - Auto-charting maps, or any agent-driven map work; maps stay HITL. - Herdr-cli pane/worktree orchestration for the eventual autonomous loop. ## Further Notes - The design (ADR-0092..0096 + `docs/os-backlog-lifecycle.md`) is merged to main; implementation is unblocked. - The work is ticketed as child issues carrying `Spec: #250`, sequenced by `Blocked by #NNN` lines: templates → capture/validator(+shared lib) → sweep → refine/check-out, with close-protocol and wayfinder-docs unblocked from the start. - Declined review findings (recorded deliberately, per no-speculative-hardening): atomic compare-and-claim, revision-precondition label mutations, adapter contract tests with recorded payloads, live-tracker integration tests — single-user tracker; assignee check + cheap reversal + comment-first idempotency cover the realistic failures.
Author
Owner

Resolution

Done: Spec parent complete: all child tickets (#251-#257, #261, #256) shipped — templates, capture/validator + shared lib, decision-sweep, close protocol, wayfinder docs, and finally the check-out protocol.

Evidence: branch main, commit 32ef3e6 (final child #256); design docs/os-backlog-lifecycle.md + ADR-0092..0096 merged earlier (ea9d019)

Follow-ups: #262 (sweep tracker-adapter fixes), #315, #316 remain open as post-spec follow-ups; refine-skill enhancements shipped under #255 — none dropped.

## Resolution **Done:** Spec parent complete: all child tickets (#251-#257, #261, #256) shipped — templates, capture/validator + shared lib, decision-sweep, close protocol, wayfinder docs, and finally the check-out protocol. **Evidence:** branch main, commit 32ef3e6 (final child #256); design docs/os-backlog-lifecycle.md + ADR-0092..0096 merged earlier (ea9d019) **Follow-ups:** #262 (sweep tracker-adapter fixes), #315, #316 remain open as post-spec follow-ups; refine-skill enhancements shipped under #255 — none dropped.
jared closed this issue 2026-08-07 13:15:18 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#250
No description provided.