# Design: retire-planka-git-issues-only ## Context os-backlog today (post-slice-8, 2026-07-13): Ruby lib + CLI over both a Planka board model (board-ensure/resolve/card-*) and tracker inspection (`inspect`, `tracker.rb`, `project_index.rb`), skills (capture/list/route), two Planka agents, a SessionStart rules note (~447 tokens), an os-status grammar check, and a wakeup poller that already reads git issues. ADR-0042 retires the Planka half. The issue-side plumbing (`tea` for Forgejo, `gh` for GitHub, in-repo files for `repo:`) already exists and is what real work has used. Constraint: the plugin is globally installed and ambient on every machine — the rework must land whole (no half-migrated grammar), and source edits require `bin/refresh-plugins` to reach sessions. ## Goals / Non-Goals **Goals:** - One tracker per project holds both state and specs; `planka:` gone from the grammar. - Preserve the durable process contracts: mid-session capture, pull-only listing, priority + autonomy labels, human-only curation gate, cross-project filing. - Leave zero dormant Planka infrastructure: cards migrated, server down, gem archived, credentials revoked. **Non-Goals:** - A unified dashboard over git issues (explicitly deferred until it is a felt pain point). - Reworking the wakeup poller (already issue-based; only its label reads are re-checked). - Bulk re-onboarding of projects beyond rewriting their `tracker=` values. - Any new home for client management (Invoice Ninja et al. own that; out of scope). ## Decisions 1. **State model = open/closed + labels, no status-label state machine.** Columns Backlog/Next/Doing/Waiting/Review/Done collapse to: open issue (backlog), `next` label (human-curated), assignee/linked-branch activity (doing — no label to maintain), `waiting` label + a blocker comment, `review` label (semi work shipped), closed (done). Rationale: every label the AI must maintain is a compliance cost the incentives review flagged; keep only labels that carry information a human filters on. Alternative rejected: full column-equivalent label set (`doing`, `done`) — duplicates what issue state and assignment already express. 2. **Curation gate: `next` is human-only in skill/hook prose, not CLI-enforced.** ADR-0029's CLI enforcement existed because Planka moves were CLI-mediated; issue labels are set via tea/gh which os-backlog does not proxy. The rule lives in the SessionStart note + skills, and the session-audit rubric (os-context category 8) measures compliance. Alternative rejected: wrapping tea/gh in an enforcing CLI — rebuilds the proxy layer the retirement is deleting. 3. **Non-repo/ops work: a private `ops` Forgejo repo, `tracker=forgejo:jared/ops`.** The recurring Operations card becomes a recurring-convention issue there (comment + reopen/leave-open, never close — mirrors the existing recurrence contract). Alternative rejected: `repo:` files — loses labels and the wakeup/query surface for the one place recurring process work lives. 4. **Migration before demolition, human gate on client data.** Card migration runs while Planka is still up; philly-search-engine-marketing (23 cards, real client backlog) is migrated only after per-card human sign-off (destination: the client project's tracker or the ops repo). cc-os non-Done cards → Forgejo `jared/cc-os` issues. Done cards are not migrated (history stays in a final JSON snapshot archived to the ops repo before decommission). Rollback: the snapshot + a Postgres dump taken before server teardown. 5. **Code removal is deletion, not deprecation.** `board_ensurer/board_resolver/ board_spec/cards` (Planka transport), both agents, and gem wiring are deleted with their tests; `tracker.rb`/`inspector.rb`/`config.rb`/`project_index.rb`/`wakeup.rb` survive. `Config#planka_board` and `Resolver` board logic go. Grammar validation rejects `planka:` with a pointer to ADR-0042. Alternative rejected: feature-flagging Planka off — dormant-code variant of the dormant-server trap. 6. **planka-api gem: archive the repo, keep no dependency.** The gem is user-authored and unpublished; archival (read-only, README pointer to ADR-0042) preserves the reverse-engineering knowledge without implying maintenance. The vault gotchas note stays — it documents the API, not our use of it. ## Risks / Trade-offs - [Untested non-repo workload loses its designated surface] → ops-repo issues are the cheap test ADR-0042 calls for; revisit via a new ADR if it chafes in practice. - [AI label discipline unenforced] → session-audit rubric already measures tracker-routing compliance; the label contract is smaller than the column contract it replaces (fewer states, fewer rules). - [Client board migration loses nuance (comments, label history)] → per-card human gate; full JSON snapshot archived first. - [Stragglers: `.cc-os/config` files on other machines still saying `planka:`] → config-write/os-status check rejects the value with a one-line re-route instruction; fail-soft, never blocks a session. - [Forgejo becomes a single point of failure for process state] → it already was for specs and wakeup; repos sync to it from every machine and it is backed up with the VPS. ## Migration Plan 1. Land the plugin rework + spec deltas (tests green, `bin/refresh-plugins`). 2. Snapshot all boards to JSON; archive snapshot in the ops repo; Postgres dump on ovh-vps. 3. Create `jared/ops` repo + label set; move the recurring audit issue there. 4. Migrate cc-os non-Done cards → `jared/cc-os` issues (labels carried over). 5. Human-gated pass over philly-search-engine-marketing cards. 6. Rewrite `tracker=` in onboarded projects' `.cc-os/config`. 7. Revoke bot credentials; decommission Planka on ovh-vps; archive the gem repo. 8. Update docs: implementation-status leaf + index line, CLAUDE.md inventory line, backlog-pilot vault note. Rollback (any step before 7): Planka is still running; restore config values. After 7: restore from Postgres dump — accepted as effectively one-way once step 7 runs. ## Open Questions - Whether `philly-search-engine-marketing` cards land in a client repo tracker or the ops repo (human decision during step 5). - Which machine's cron (if any) hosts the wakeup poller — pre-existing open item, not blocked by this change.