From 1d2313b98c4e2e20a438394dd6455b7d34427310 Mon Sep 17 00:00:00 2001 From: didericis Date: Thu, 28 May 2026 21:51:21 -0400 Subject: [PATCH] docs(research): issue tracking vs in-repo decision history Analyze tracking feature requests in Gitea against the project's in-repo PRDs/research notes, given the goal of keeping decision history portable and not provider-locked. Recommends demoting issues to an ephemeral inbox and reifying durable rationale into the repo. Co-Authored-By: Claude Opus 4.8 --- ...ue-tracking-vs-in-repo-decision-history.md | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 docs/research/issue-tracking-vs-in-repo-decision-history.md diff --git a/docs/research/issue-tracking-vs-in-repo-decision-history.md b/docs/research/issue-tracking-vs-in-repo-decision-history.md new file mode 100644 index 0000000..fb3f4a6 --- /dev/null +++ b/docs/research/issue-tracking-vs-in-repo-decision-history.md @@ -0,0 +1,196 @@ +# Tracking feature requests in Gitea vs. in-repo decision history + +Research into whether bot-bottle should track feature requests (and the +decision-making around them) as Gitea issues, given that the project +already records specs in-repo as PRDs (`docs/prds/`) and rationale as +research notes (`docs/research/`). The stated constraint is that the +*history of why we decided things* should be durable and portable — +not locked into a single forge (Gitea today, conceivably GitHub or +something else tomorrow). + +## Summary + +Keep using issues, but demote them. The repository — not the forge — is +the system of record for any decision you would be unhappy to lose. +Issues are an excellent **inbox and coordination surface** (cheap +capture, triage, async discussion, notifications, auto-linking) and a +**poor archive** (provider-locked storage, brittle numeric references, +rationale stranded in comment threads). The failure mode to avoid is the +one already present in the repo: a PRD whose reasoning is only complete +if you also read a Gitea issue thread. + +The fix is a discipline, not a tool: **every load-bearing decision gets +reified into a versioned file in the repo before the issue that prompted +it is closed.** PRDs already do this for features; the gap is (a) small +requests that never merit a PRD and (b) decisions that aren't features +at all (e.g. "we merge with rebase," "author identity is claimed-not- +vouched"). Close that gap with a lightweight in-repo decision log. Then +issues can be as disposable as the forge makes them, and migrating +forges costs you triage state, not history. + +## Why this even comes up here + +The project already leans on the repo for durable artifacts: + +- **PRDs** (`docs/prds/0001…0027`) — the spec and its rationale. +- **Research notes** (`docs/research/`) — the "why," with tradeoffs. +- **Conventional-commit history** — a machine-greppable change log. + +But the issue layer has quietly become load-bearing in places: + +- PRD 0025 says it picked "option 3" *"from the #88 design + discussion"* and that the rejected alternative lives "in issue #88's + comment thread." The PRD's rationale is therefore **incomplete without + the issue**. If Gitea is gone, the strongest argument for the chosen + design is gone with it. +- PR #89's description links `…/didericis/claude-bottle/issues/88` — + the **pre-rename** repo path (the project was Codex-bottle/claude- + bottle before the bot-bottle rebrand). That link is already + half-dead: a concrete demonstration that forge URLs rot under the + most routine event imaginable, a rename. +- Issue/PR numbers (`#88`, `#90`, `#94`, `#95`) are **forge-assigned + from a shared sequence**. They cannot be reconstructed from a clone, + and they collide/renumber on import into a different tracker. + +So the question isn't academic. The current practice is already +producing references that don't survive a rename, let alone a migration. + +## What each medium is actually good at + +| Concern | Gitea issue | In-repo file (PRD / note / log) | +|---|---|---| +| Capture friction | Near-zero — file a one-line idea | High — a PRD is a heavy artifact; a note less so | +| Triage (labels, milestones, open/closed, assignee) | Native, good | Absent / hand-rolled | +| Async discussion + notifications | Native (threads, @mentions, watch) | None — needs a PR review or out-of-band chat | +| Auto-linking (`Closes #N`, PR↔issue, commit↔issue) | Native | Manual cross-reference | +| Version control of the content | None — lives in Gitea's DB | Full — diff, blame, branch, revert | +| Travels with `git clone` | No | Yes | +| Survives forge migration | Degrades (export/import; threads, authors, timestamps, refs lossy) | Unaffected | +| Survives forge outage | Inaccessible | Local clone has it | +| Greppable offline / by tooling | Only via API | `grep docs/` | +| Reproducible identifiers | Forge-assigned numbers | Filenames you control (`0027-…`) | + +The split is clean: **issues win on the live, social, coordination axes; +the repo wins on every durability and portability axis.** Nothing about +that table says "pick one." It says "use each for what it's good at, and +don't let the durable thing depend on the ephemeral one." + +## Lock-in failure modes (the cons, concretely) + +1. **Stranded rationale.** The single most valuable output of a feature + discussion — *why we rejected the obvious alternative* — usually + emerges in a thread and dies there unless someone copies it into the + spec. PRD 0025 is already in this state. +2. **Reference rot.** `Closes #88` / "see issue #90" are meaningful only + against one forge instance at one point in time. A rename already + broke one such link; a migration would break all of them and + silently renumber the survivors. +3. **Two sources of truth.** A PRD carries `Status: Draft`; the issue + carries open/closed. They drift. Which is authoritative? +4. **Availability coupling.** Self-hosted Gitea down (or the Tailscale + path to it down) means the backlog and its history are unreachable, + even though the code and PRDs are right there in the clone. +5. **Export is lossy.** Gitea→GitHub (or the reverse) moves issue *text* + tolerably but mangles cross-references, comment authorship for + non-mapped users, timestamps, and reactions. The graph of "#88 → PR + #89 → commit abc" does not survive intact. + +None of these are arguments against *having* issues. They're arguments +against issues being the **only** place a decision is recorded. + +## Pros of keeping issues anyway + +Worth stating plainly, because "just use the repo for everything" +overcorrects: + +- A PR per half-formed idea is absurd; issues are the right weight for + "someone should look at X someday." +- Triage state (priority, milestone, assignee, open/closed) is genuine + project-management value the repo does not natively provide. +- Notifications and threaded discussion are how a decision *gets made* + before it's ready to be written down. Killing issues doesn't move that + conversation into the repo — it moves it into chat/DMs, which is + *worse* for durability, not better. +- `Closes #N` automation and PR↔issue linkage are real ergonomics. + +The goal is not to abandon the tracker. It's to make sure that when the +tracker eventually goes away, you lose the *backlog*, not the *history*. + +## What belongs where + +- **Gitea issue** — intake, triage, status, and the live discussion. + Treat it as a **cache**: useful now, expendable later. +- **PRD (`docs/prds/`)** — the durable spec for anything that warrants + one. Rule: a PRD must be **self-contained**. Synthesize the issue + discussion into the Problem / Design / Open-questions sections; + reference the issue as a convenience pointer, never as the only home + of a load-bearing argument. (Retrofit PRD 0025: inline the #88 + "option 3 vs `bottle_config:`" reasoning so the PRD stands alone.) +- **Research note (`docs/research/`)** — the durable "why," exactly like + this file. Comparative analysis, landscape surveys, tradeoffs. +- **Commit message** — the durable "what changed and why, at this point + in the diff." +- **Decision log (proposed, see below)** — durable record of decisions + that aren't features and don't merit a PRD. + +## Closing the gap: a portable decision record + +Two classes of decision currently have no in-repo home: + +- **Sub-PRD feature requests** — too small for a PRD, but you still want + a tracked "we will / won't do this, because." Today these live only as + issues. +- **Non-feature decisions** — "merge with rebase, not merge-commit," + "agent identity is claimed-not-vouched," "bottles are home-only." + Some land inside a PRD that happens to touch them; many are folded + into chat and lost. + +Options, cheapest first: + +1. **An ADR-lite log under `docs/decisions/`.** One short Markdown file + per decision: context, decision, consequences, date, links. This is + the industry-standard Architecture Decision Record pattern, and it's + a near-exact fit for "track decision history, portably." Numbered + like PRDs (`0001-merge-with-rebase.md`). ~10 lines each; the + discipline is writing them, not the format. +2. **Reuse the journal.** The repo ships an `init-entry` skill that + writes timestamped prose to `docs/JOURNAL.md` (not yet created here). + A stream-of-thought journal is a fine home for decision *narrative* + and is already part of the toolchain — lower ceremony than ADRs, less + structured for later retrieval. The `tag-entries` skill could tag + decision entries for grep-ability. +3. **Periodic issue export.** Belt-and-suspenders: a scheduled job hits + the Gitea API and dumps open/closed issues + comments to JSON under + `docs/issues-archive/`, committed. Preserves the raw thread against + forge loss without changing daily workflow. Mechanical, not a + substitute for reifying rationale (a JSON dump of a thread is + evidence, not a decision). + +These compose: ADRs/journal for the *decision*, optional export for the +*raw evidence*, issues for *live coordination*. + +## Recommendation + +1. **Keep Gitea issues for intake, triage, and discussion.** Don't fight + the forge on the things it's good at. +2. **Make the repo the system of record.** Adopt the rule: no decision + is "done" until its rationale exists in a versioned file (PRD, + research note, or decision log). The issue is a pointer, never the + sole source. +3. **Add `docs/decisions/` (ADR-lite).** Smallest change that closes the + real gap — sub-PRD requests and non-feature decisions. Start by + back-filling the few decisions already made only in threads or chat + (rebase-merge policy; the agent-identity trust call from PRD 0027). +4. **Retrofit PRD 0025** to inline its #88 rationale, removing the one + existing hard dependency on a forge thread. +5. **Treat issue numbers as disposable.** When a PRD/commit cites an + issue, ensure the cited content is mirrored in-repo so the citation + degrades to a dead-but-harmless link, not lost information. (The + already-broken `claude-bottle/issues/88` link is the warning.) +6. **Optional:** automate a Gitea issue export into the repo if you want + the raw threads preserved without manual transcription. + +Net: issues stay, because the alternative to issues is chat, which is +worse. But the project's durable memory must live where the project +already lives — in the clone — so that switching forges, or losing one, +costs you a backlog you can rebuild, never a history you can't.