cc-os/docs/implementation-status/os-backlog.md

129 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# os-backlog — component detail
_Leaf file of [../implementation-status.md](../implementation-status.md). Read on demand._
**Global os-backlog plugin**`cc-os/plugins/os-backlog/` (git-tracked, 2026-07-10);
symlinked into `~/.claude/plugins/os-backlog`; PRD Forgejo issue #9 (state pointer: Planka
card `1816234194716592051`), slices #10#17. Decision records: ADR-0023 (own plugin, not an
os-vault extension), ADR-0025 (standard Ruby plugin structure), ADR-0029 (card-move +
column ownership).
## Component inventory
- Purpose: the AI's process-management surface over Planka — deterministic tracker routing
(Planka = task state by default; git issues = implementation specs only), mid-session
capture, pull-only listing, board lifecycle, and the three-value autonomy convention
(`hitl`/`semi`/`afk-ready`; amended per ADR-0029: afk-ready ships straight to Done, semi
stops at Review).
- Lib (Ruby, os-adr `lib/`+`bin/` pattern, installed planka-api gem only — no source
coupling): `board_spec.rb` (uniform lists/labels contract), `board_ensurer.rb`
(idempotent create/repair; Planka 2.1.1 `type` fields, shared-project + owner-manager
visibility fix, label color candidates with fallback; `archived--` rename convention),
`config.rb` (`.cc-os/config` parser), `resolver.rb` (pure repo→board decision:
`use`/`activate`/`stop-and-discuss`; no network), `cards.rb` (add-at-Backlog, snapshot,
attach_label, comment, move with ownership rules), `tracker.rb` + `inspector.rb`
(2026-07-12, issue #14 — tracker-format validation/remote classification + in-repo
issue-file discovery; `Config.merge` preserves other keys).
- CLI: `bin/os-backlog``board-ensure`, `activate`, `archive`, `resolve`, `card-add`,
`cards`, `snapshot`, `card-label`, `card-comment`, `card-move` (2026-07-12, ADR-0029),
`inspect`, `config-write`; every path fails soft (one-line error, exit 1) when the
gem/Planka is unavailable.
- Skills: `/os-backlog:capture`, `/os-backlog:list` (pull-only per notification policy v2),
`/os-backlog:route` (2026-07-12, issue #14 — tracker onboarding conversation; destination
choice + live-history migration are named human gates) — carry the column-ownership rules
(AI creates at Backlog, Doing→Review at most, never Next, never self-assigns `hitl`;
"working a card means moving it" contract added 2026-07-12).
- Agents: `agents/card-triage.md` (priority + autonomy labels only; ambiguity → `hitl`),
`agents/board-audit.md` (four drift classes; writes at most comments).
- Tests: `tests/` — 68 runs/153 assertions as of 2026-07-12 (35 → 54 → 58 → 68 across the
slices) against an in-memory `FakePlankaClient`; no live API. Companion os-status check
`tracker-configured` (issue #11) validates the `tracker` key grammar and nudges
unconfigured git projects (daily-snoozed).
## Build and verification history
- **AFK slices shipped (2026-07-10):** #10 plugin scaffold + `board-ensure` (uniform
lists/labels incl. new `semi` autonomy label), #11 `tracker` key in `.cc-os/config` +
os-status check, #12 pure routing resolver CLI, #13 capture/list skills + card CLI, #15
`card-triage` + `board-audit` named agents. Live verification same day: planka-api gem
0.1.0 installed locally (`rake install`, rbenv 4.0.2; publish/versioning parked behind gem
issue 13); `snapshot`, `board-ensure` (created the missing `semi` label on the cc-os
board), `card-add` + `card-label` all succeeded against production Planka with bot
credentials sourced from ovh-vps (`~/services/planka/bot-credentials.env`) in a subshell.
Follow-up captured as a `hitl` Backlog card: get planka_bot into credvault (no import
path — rotate vs. add import capability is a human decision).
- **planka-api 0.2.0 typed-returns migration (2026-07-10, commit `8df0cb7`):** 0.2.0 returns
`Planka::Types` value objects instead of parsed-JSON hashes. `board_ensurer.rb` and
`cards.rb` rewritten on typed accessors; `Cards#snapshot` builds explicit string-keyed
hashes from `BoardDetail#lists`/`#cards`/`#labels`/`#card_labels`. Test fakes rebuilt to
return real `Planka::Types` records. JSON output stays byte-compatible, so skill/agent
contracts are unchanged. Follow-up fix (issue #18, same day): the migration had silently
dropped one field from the per-card snapshot hash; restored the full 19-key camelCase card
key set plus `labels`, with a regression test pinning the key set including
`listChangedAt`.
- **Live verification 0.2.0 (2026-07-10, issue #20):** local machine had no `PLANKA_*`
env/credvault entry, so the plugin tree was rsynced to `ovh-vps:/tmp/os-backlog-verify`
and exercised there with bot credentials sourced in a subshell (contents never read or
printed). Results: tests 35 runs/0 failures on ovh-vps; `board-ensure cc-os` idempotent
(twice `(existing)`, nothing created); card-add/card-label/card-comment/snapshot all
correct with the full 20-key set; test card deleted via `Planka::Client#cards.delete`
(the CLI has no delete subcommand) and confirmed gone; verification tree removed. No
regressions vs. pre-0.2.0.
- **Slice 7 (2026-07-13, issue #16):** SessionStart injection note shipped
(`hooks/session_start.py` + `hooks/hooks.json`, os-adr-style plugin-local hook): WHEN→THEN
rules for capture / routing / promotion / column ownership / autonomy labels, ADR-0029
semantics (the issue body's "afk-ready → Review" was wrong — caught in Codex review),
rules only, zero board state, ~447 tokens. `/to-issues` (global skill,
`~/.agents/skills/to-issues/`) gained a destination-tracker step reading the
`.cc-os/config` tracker key; the `planka:`/unset default publishes slices as git issues
on the repo remote + one Planka pointer card (spec/state boundary preserved — human gate
decided 2026-07-13). `Backlog::Tracker.issues_destination` + 6 routing tests.
- **Board-id cache (2026-07-13, issue #22):** `Backlog::BoardResolver` with injected config
read/write lambdas; `board_id=` cached in `.cc-os/config` beside `tracker=` (name stays
source of truth; id honored only for `planka:` trackers and validated against the
returned board name; 404/mismatch/any cache failure degrades to name lookup and rewrites
the cache; write failures never fail the command). Comment-preserving `Config.set`
mirrors os-status's writer. 14 new tests; suite 90 runs / 198 assertions / 0 failures.
- **Slice 8 (2026-07-13, issue #17):** Operations board created in the Dev project (board
`1818308120145822783`) with uniform lists/labels; recurring card "Biweekly orchestration
IRL audit (recurring)" (card `1818310715438531668`, P2 + semi, first progress comment
`1818310889929966683`; recurrence contract: comment + move back to Backlog, never Done).
Tracker-routing convention canonized as **ADR-0033** (Planka = state / git issues = specs,
tracker key grammar, pointer + promotion rules; cites route/to-issues/session-start
rather than restating). os-context audit rubric gained category 8 `tracker-routing`
(capture/route/promote compliance only). Bug found live and fixed: label color fallback
only rescued `Planka::ValidationError`, but Planka rejects unknown colors as HTTP 400
`Planka::BadRequestError` — fallback now rescues both (regression test; suite 91 runs /
0 failures). os-status `/os-status:fix` step d reworded: invoke `/os-backlog:route`
directly, never pre-ask "forgejo or planka?" (boundary rule uses both — surfaced by the
servers-repo onboarding, cf. issue #26).
- **Issue-shape classification (2026-07-13, issue #26):** `inspect` now fetches lightweight
remote-issue metadata (tea `--output json` with string-index/joined-labels normalization;
gh `--json`; fail-soft → nil) and emits an always-present `issue_shape` key
(`sequential-chain` / `flat-adhoc` / `mixed` / null). Classification is a pure
`Inspector.classify_issue_shape` (label allowlist with whole-token matching; cross-refs
must hit the fetched set with dependency language within 40 chars; <3 issues or no
metadata null). Route SKILL.md step 2 rewritten as three branches with **split as the
default** for spec-shaped issue sets (still exactly one tracker key division of labor,
not two destinations); step 3 got a never-re-trigger exception; boundary rule now cites
ADR-0033 instead of restating it. 12 new tests incl. a CLI-contract test; suite 103 runs /
212 assertions / 0 failures.
- **Cross-project filing (2026-07-13, issue #27, ADR-0034):** `Backlog::ProjectIndex`
derived global index at `~/.cc-os/projects.json` (atomic temp+rename writes, corrupt/
missing empty, `CC_OS_HOME` override), upserted fail-soft by config-write (canonical
path via `git rev-parse --show-toplevel`), queried via new `projects [filter]` CLI
subcommand. Discoverer template + tea/gh/card-add mechanics in
`skills/route/references/cross-project-filing.md`; one CROSS-PROJECT rule line added to
the SessionStart note. 9 new tests; suite 112 runs / 233 assertions / 0 failures. Live
smoke: cc-os row present in the real index.
- **Wakeup design spike (2026-07-13, issue #28, ADR-0035/0036):** poll + tmux direction
chosen at the human gate. `Backlog::Wakeup` + `bin/wakeup-poll` thin pilot (dry-run
default, `--spawn` to create `cc-<project>-issue<N>` tmux sessions and persist
`~/.cc-os/wakeup-state.json`; opt-in `wakeup=true` in `.cc-os/config`; afk-ready act,
semi triage-only, else notify-only into pull-only `~/.cc-os/wakeup-summary.md`). No
cron installed; 6 tests; suite 128 runs / 0 failures. Follow-up recorded: single
designated poller machine (state stays per-host); cadence/cron mechanism and a
`config-write` wakeup key deferred until a first project opts in.
- **Outstanding:** #14 residual (onboard one more project operational hitl); wakeup
rollout (first opt-in project + poller machine + cadence).