# 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.
