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

162 lines
12 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, slices #10#17.
Decision records: ADR-0023 (own plugin, not an os-vault extension), ADR-0025 (standard Ruby
plugin structure), ADR-0029 (column ownership — subject removed by ADR-0042), **ADR-0042
(2026-07-16, supersedes ADR-0033): Planka retired; git issues are the single tracker for
state and specs** (OpenSpec change `retire-planka-git-issues-only`).
## Component inventory (post-ADR-0042, v0.3.0)
- Purpose: the AI's process-management surface over git issues — deterministic tracker
routing (`forgejo:<owner>/<repo>` | `github:<owner>/<repo>` | `repo:<path>`; `planka:`
rejected fail-soft citing ADR-0042), mid-session capture as labeled issues, pull-only
listing, cross-project filing via the global project index.
- State model: open/closed + labels. Ten canonical labels: priority `P0``P3`; autonomy
`hitl`/`semi`/`afk-ready` (semi ships to `review` label and stays open; afk-ready closes
after verification); state `next` (human-only — AI never applies/removes), `waiting`
(+ blocker comment), `review`. No `doing`/`done` labels: in-progress = assignment/branch
activity, done = closed. Recurring-convention issues (e.g. `jared/ops#1` biweekly audit)
are commented per occurrence and never closed by the AI.
- Lib (Ruby): `tracker.rb` (grammar validation + `issues_destination`: `:git_issues` /
`:repo_files` / `:unrouted`), `issues.rb` (2026-07-16 — capture/list dispatch: `tea` for
forgejo, `gh` for github, `NNN-<slug>.md` frontmatter files for `repo:`; injected runner,
no state labels reachable through `create`), `inspector.rb` (issue-shape classification),
`config.rb`, `resolver.rb` (reduced to tracker-presence decision), `project_index.rb`,
`wakeup.rb`.
- CLI: `bin/os-backlog``resolve`, `inspect`, `config-write`, `projects`, `issue-create`
(`--title/--body/--priority`), `issues` (grouped next/waiting/review/other). Fail-soft
one-liners throughout.
- Skills: `/os-backlog:capture` (issue-create; never state labels, never `next`),
`/os-backlog:list` (pull-only), `/os-backlog:route` (destination proposal + idempotent
ten-label ensure via tea/gh). SessionStart note rewritten 2026-07-16 (~444 tokens,
down from ~687 measured): capture / routing / cross-project / human-only-`next` /
working-state / autonomy / recurring rules.
- Tests: 88 runs / 203 assertions (2026-07-16) with fake CLI runners; no live API.
Companion os-status `tracker-configured` check validates the reduced grammar and rejects
`planka:` with the ADR-0042 advisory.
## 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` (now `to-tickets`; global skill,
then at `~/.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-tickets/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 = realpath of the directory the config was written into NOT the git toplevel, so
umbrella subprojects index as themselves; corrected 2026-07-13 review), queried via new
`projects [filter]` CLI subcommand (filter matches name, tracker, or path). 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.
- **Review corrections (2026-07-13, cards #1818330518584820864 / #1818330528525321347):**
post-ship review (Codex + verification pass) of the triage hook and project index:
`Config#planka_board` (`tracker=planka:<board>` now counts everywhere, incl. the
Resolver, not just the explicit `board` key); triage hook board resolution moved to pure
`TriageCheck.board_name_for` honoring the umbrella rule (session cwd's `.cc-os/config`
overrides the git root's; hook previously read only the root config); index keying fixed
per above; hook timeout 8→15s; `CC_OS_DEBUG=1` surfaces swallowed hook errors on stderr.
Known residual (captured as a Backlog card): board lookup is name-only across ALL Planka
projects — duplicate board names in different projects can resolve to the wrong board.
Suite 138 runs / 295 assertions / 0 failures.
- **Planka retirement rework (2026-07-16, ADR-0042, OpenSpec change
`retire-planka-git-issues-only`):** after a week live, all real work flowed through git
issues while boards held only the plugin's own build cards — Planka retired. Deleted:
`board_ensurer`/`board_resolver`/`board_spec`/`cards`/`triage_check` (+ triage hook),
both agents, planka-api gem wiring, `FakePlankaClient`, nine card/board CLI subcommands.
Added: `issues.rb` + `issue-create`/`issues` CLI (live-verified; fixed tea field
`assignees``assignee` is not a valid tea list field). Skills + SessionStart note +
`/to-issues` + os-status fix skill rewritten to the single-tracker model. Migration:
all 9 boards snapshotted (JSON + comments) + Postgres dump on ovh-vps; snapshot archived
in new private `jared/ops` Forgejo repo (canonical labels; recurring audit issue
`jared/ops#1`); cc-os non-Done cards → issues jared/cc-os#6170 (3 skipped: pointer to
closed #25, duplicate of open #8, obsoleted board-lookup card); ovh-prod + ruby-gems
strays → jared/ops#23; `planka` board's 18 cards obsolete (gem build history, covered
by snapshot); `tracker=` rewritten in all 6 indexed projects (no `planka:` values
remain). Suite 88 runs / 203 assertions; os-status 80 tests.
- **Human gates closed (2026-07-16):** philly per-card pass done — 4 repo cards →
jared/llf-schema#710, 18 client cards → jared/ops#421, guardrails pin closed (vault
note is the record). Decommission done same day: bot creds deleted, Planka
containers/cron/service dir removed from ovh-vps (snapshot + pg dump + service configs
kept at `~/planka-final-snapshot-2026-07-16/`), github.com/jaredswanson/planka archived
read-only with an ADR-0042 README banner.
- **Outstanding:** #14 residual (onboard one more project — operational hitl); wakeup
rollout (first opt-in project + poller machine + cadence); jared/cc-os#74 — fold
ADR-0025 compliance into os-backlog (bin/wakeup-poll second entry point, README gem
deps), filed by the standards audit.