diff --git a/docs/INDEX.md b/docs/INDEX.md index 0a359c6..5cab3dc 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -1 +1 @@ -Research notes live in `research/`. Product requirement docs live in `prds/`. +Research notes live in `research/`. Product requirement docs live in `prds/`. Decision records (ADR-lite) live in `decisions/`. diff --git a/docs/decisions/0001-merge-prs-with-rebase.md b/docs/decisions/0001-merge-prs-with-rebase.md new file mode 100644 index 0000000..283472a --- /dev/null +++ b/docs/decisions/0001-merge-prs-with-rebase.md @@ -0,0 +1,47 @@ +# ADR 0001: Merge PRs with rebase, not merge commits + +- **Status:** Accepted +- **Date:** 2026-05-28 +- **Deciders:** didericis + +## Context + +PRs need a merge strategy. Gitea offers merge-commit, squash, rebase, +and rebase-merge. The project uses [Conventional +Commits](https://www.conventionalcommits.org/) enforced by a +`commit-msg` hook, and PRDs typically land as a multi-commit PR where +each commit is meaningful on its own (e.g. PR #95: a `docs(prd)` commit, +a `feat(manifest)` implementation commit, and a `docs(manifest)` +commit). The history should stay readable and the individual +conventional commits should survive onto `main`. + +## Decision + +Merge PRs with **rebase** (Gitea's `rebase` style; `Do: "rebase"` via +the API). The branch's commits are replayed onto `main` with no merge +commit, producing a linear history that preserves each commit verbatim. + +## Consequences + +- **Linear history**, no merge bubbles; `git log --oneline` reads as a + straight sequence of conventional commits. +- **Each commit is preserved** (unlike squash, which would collapse the + PRD/impl/docs commits into one and lose the staged structure). +- **Commit SHAs are rewritten at merge.** The replayed commits on `main` + get new SHAs, and the source branch is deleted, so a link to a file + by *branch name* (`/src/branch//…`) dies at merge. This is + why links to not-yet-merged files are pinned to a **commit SHA** + (`/src/commit//…`), which stays reachable via the retained + `refs/pull//head` ref. See + `docs/research/issue-tracking-vs-in-repo-decision-history.md`. +- **Trade-off accepted:** without a merge commit, the "these commits + landed together as PR #N" grouping is not recorded in git itself — it + lives in forge state (the PR). That is a mild concession against the + keep-history-in-the-repo posture; the conventional-commit scopes and + PRD references in the messages keep changes traceable without it. + +## Links + +- `docs/research/issue-tracking-vs-in-repo-decision-history.md` — the + commit-pinning consequence above. +- Observed practice: PRs #92, #93 merged with rebase; #95 to follow. diff --git a/docs/decisions/0002-agent-identity-claimed-not-vouched.md b/docs/decisions/0002-agent-identity-claimed-not-vouched.md new file mode 100644 index 0000000..556f267 --- /dev/null +++ b/docs/decisions/0002-agent-identity-claimed-not-vouched.md @@ -0,0 +1,48 @@ +# ADR 0002: Agent-set git identity is claimed, not vouched + +- **Status:** Accepted +- **Date:** 2026-05-28 +- **Deciders:** didericis + +## Context + +PRD 0027 lifts `git.user` (name/email) to the agent layer, so an agent +file may declare its own commit identity. Agent files can live in +`$CWD/.bot-bottle/agents/` — i.e. they can be supplied by a cloned, +less-trusted repository. That raises the question of whether a +repo-supplied agent setting its own git identity is a security concern, +and whether agent identity should be gated differently for `$CWD` +agents than for `$HOME` agents. + +This record exists because the decision is a **trust posture** worth +finding on its own, separate from the feature PRD that introduced it. +The full analysis lives in PRD 0027; the decision is summarized here. + +## Decision + +Allow agents to set `git.user`, and treat an agent-declared identity as +**claimed, not vouched**. No `$CWD`-vs-`$HOME` gating on the identity +field. `git.remotes` stays bottle-only (home-only). + +## Consequences + +- A cloned repo's agent file can present any commit author name/email, + including one that reads like a real person's. This is accepted: git + authorship is **not a credential** (push auth is the bottle's remote + key/token), is **already forgeable** from inside the bottle at runtime + (`git config user.email …`), and was never a trust anchor. +- If attribution integrity ever matters, the answer is commit + **signing** (SSH/GPG), not the author field — so this decision closes + no door that was open. +- `git.remotes` is deliberately *not* lifted to the agent layer: it + carries credentials and host trust (IdentityFile, KnownHostKey) and + remains a bottle-only, home-only concern. +- Revisit if a future change ever makes commit identity load-bearing + (e.g. enforced signing keyed on author), at which point gating + `$CWD`-supplied identities would matter. + +## Links + +- PRD 0027 (`docs/prds/0027-agent-git-user-identity.md`) — full trust + analysis and schema. +- Issue #94, PR #95 — the feature this decision was made for. diff --git a/docs/decisions/README.md b/docs/decisions/README.md new file mode 100644 index 0000000..3b4cf03 --- /dev/null +++ b/docs/decisions/README.md @@ -0,0 +1,56 @@ +# Decision records + +Short, durable records of decisions — one file per decision. This is a +lightweight [Architecture Decision Record](https://adr.github.io/) +practice: capture *what was decided and why* in a versioned file so the +reasoning lives in the clone, not in a forge issue thread or a chat log +that disappears when the provider does. + +See `docs/research/issue-tracking-vs-in-repo-decision-history.md` for +the rationale behind keeping decision history in-repo. + +## When to write one + +| Artifact | For | +|---|---| +| **PRD** (`docs/prds/`) | A feature: what to build, scope, success criteria. | +| **Research note** (`docs/research/`) | A landscape/tradeoff investigation. | +| **Decision record** (`docs/decisions/`) | A decision that isn't itself a feature — a policy, a convention, a "we will / won't do this," or a load-bearing choice made inside a larger PRD that deserves to be discoverable on its own. | + +A decision that's fully specified by a PRD doesn't need duplicating +here. Write a record when the *decision* would otherwise be buried in +prose, lost in an issue thread, or have no in-repo home at all (small +requests that don't merit a PRD; non-feature choices like merge +strategy or a trust posture). + +## Format + +One Markdown file per decision, numbered sequentially and zero-padded +(`0001-…`, `0002-…`), matching the PRD numbering style. Keep it short — +the discipline is writing it down, not the ceremony. + +```markdown +# ADR 0000: + +- **Status:** Proposed | Accepted | Superseded by ADR NNNN +- **Date:** YYYY-MM-DD +- **Deciders:** + +## Context +What forced the decision; the constraints in play. + +## Decision +What we decided, stated plainly. + +## Consequences +What follows — the good, and the costs/trade-offs accepted. + +## Links +PRDs, research notes, issues/PRs. Forge links are convenience +pointers; the reasoning above must stand without them. +``` + +## Index + +- [ADR 0001](0001-merge-prs-with-rebase.md) — merge PRs with rebase, not merge commits. +- [ADR 0002](0002-agent-identity-claimed-not-vouched.md) — agent-set git identity is claimed, not vouched.