# 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:<path>` 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.
