cc-os/openspec/changes/archive/2026-07-16-retire-planka-gi.../design.md

6.3 KiB

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.