Skip to content

docs(decisions): record ADR-0021 and ADR-0022 — merge-based adoption, curation scoped to the contested surface - #308

Merged
serina-mcfall merged 1 commit into
launchpadfrom
docs/adr-0021-0022-adoption-and-curation-scope
Aug 21, 2026
Merged

docs(decisions): record ADR-0021 and ADR-0022 — merge-based adoption, curation scoped to the contested surface#308
serina-mcfall merged 1 commit into
launchpadfrom
docs/adr-0021-0022-adoption-and-curation-scope

Conversation

@tucktuck101

Copy link
Copy Markdown
Collaborator

Summary

Records two decisions @tucktuck101 took on 2026-08-22 about how this fork adopts from block/buzz: upstream is adopted by merging the vendor drop, with a decline recorded as a ledger row rather than an omitted commit (ADR-0021); and per-drop adjudication is scoped to the contested surface, with the remaining 99% adopted wholesale by stated policy (ADR-0022). Both are documentation only — no code, config or workflow changes.

Related issue

Closes #304

Refs #306 — this answers only the scope half of that issue. The drop report's shape, the unit of presentation, and whether a model writes any of it stay open, so #306 must not be closed by this PR.

Issue type

ADR


Agent provenance

Field Value
Harness / provider Claude Code
Model claude-opus-5[1m]
Session reference N/A - this harness does not expose a run id to the session
Initiating human @tucktuck101

Objective

Write launchpad/decisions/ADR-0021-merge-based-adoption-with-recorded-declines.md and launchpad/decisions/ADR-0022-curation-scoped-to-the-contested-surface.md, so two decisions taken in conversation exist as records rather than only in an issue thread.

Impacted components

launchpad/decisions/ADR-0021-merge-based-adoption-with-recorded-declines.md
launchpad/decisions/ADR-0022-curation-scoped-to-the-contested-surface.md

Approach and rejected alternatives

Two records rather than one, and that was a judgement call. The two decisions are tightly coupled — ADR-0022's "adopt the remainder wholesale" is only coherent under ADR-0021's merge-based adoption, because cherry-picking leaves no remainder. Three reasons for splitting them anyway:

  1. launchpad/decisions/README.md is explicit that it is one file per decision.
  2. They close differently. ADR-0021 closes adr: how the fork adopts upstream selectively and makes a decline durable — the vendor-branch dilemma #304 outright; ADR-0022 answers one half of adr: what the change agent produces for a vendor drop, and at what unit adoption is decided #306 and leaves the rest open. A single record closing one issue and half of another is hard to cite and easy to over-read as closing both.
  3. Whatever eventually answers the rest of adr: what the change agent produces for a vendor drop, and at what unit adoption is decided #306 will need to cite the scope ruling. A separate, numbered record gives it something to point at.

ADR-0022 names ADR-0021 as its premise in its Decision section, so the coupling is stated rather than implied.

Numbering. 0021 and 0022. ADR-0018, 0019 and 0020 are accepted but live only in unmerged PRs #268, #281 and #291, so those numbers are taken and are not reused. Verified by listing the ADR files each of those PRs adds — see the raw output below.

Rejected: waiting for #268/#281/#291 to land before numbering these. It would guarantee no collision but blocks a decided record behind three unrelated reviews, and README.md numbers by acceptance order, which these already satisfy.

Rejected: leaving Decision outcome blank. These are decided, not drafted. The blank-outcome rule in launchpad/AGENTS.md §5.1 governs an agent proposing a decision; here a human made the call and the agent is transcribing it. Provenance in both records separates what was @tucktuck101's call from what was the agent's recommendation.

Verification

Command run:

. ./bin/activate-hermit
python3 launchpad/scripts/adr_boundary_check.py; echo "exit=$?"
git log -1 --format='%B' | grep -c 'Signed-off-by'
gh pr view 268 --repo launchpad-26/buzz --json files --jq '[.files[].path|select(test("decisions/ADR"))]|join(",")'
gh pr view 281 --repo launchpad-26/buzz --json files --jq '[.files[].path|select(test("decisions/ADR"))]|join(",")'
gh pr view 291 --repo launchpad-26/buzz --json files --jq '[.files[].path|select(test("decisions/ADR"))]|join(",")'
git diff --stat launchpad/launchpad...HEAD
BODY="$(cat /tmp/pr-body.md)" LABELS='["by:agent"]' CLOSING_REFS='[304]' python3 launchpad/scripts/pr_body_check.py

Raw output:

failed: 0
exit=0
1
launchpad/decisions/ADR-0018-cohort-relay-vps-specification.md
launchpad/decisions/ADR-0019-review-checks-gate-only-when-deterministic.md
launchpad/decisions/ADR-0020-adopt-upstream-testing-methodology.md
 .../ADR-0021-merge-based-adoption-with-recorded-declines.md   | 169 ++++++++++++++++
 .../ADR-0022-curation-scoped-to-the-contested-surface.md      | 151 ++++++++++++++
 2 files changed, 320 insertions(+)
  reference: GitHub will close #304 on merge

PR body check passed. (agent)

The measurements quoted inside both records were taken on 2026-08-21 with these commands:

git ls-tree -r --name-only upstream/main | wc -l
git rev-list --count $(git merge-base launchpad/launchpad upstream/main)..upstream/main
git diff --name-only $(git merge-base launchpad/launchpad upstream/main) upstream/main | wc -l
comm -12 <upstream-touched> <fork-modified> | wc -l
git merge-tree --write-tree --name-only launchpad/launchpad upstream/main

producing: 4294 files upstream; 67 unadopted commits; 796 files those commits touch; 8 of those also modified by the fork; 4 conflicting.

  • Tests or checks were run and the raw output is pasted above
  • The diff is confined to the scope of the linked issue
  • No secrets, keys, tokens or hostnames were added to tracked files

Not verified

Security implications

No change to exposure, trust or blast radius from this diff — it adds two markdown files and no executable path, credential, endpoint or permission.

The decisions recorded do carry security implications, and both records state them at full strength rather than in summary. ADR-0021: a durable decline is durable against upstream security fixes too, so any ledger row enforced automatically as "fork always wins" must be flagged for review at each drop; ADR-0017's "whichever version is newer" position for the lefthook pin is the pattern to prefer for security-relevant rows. ADR-0022: the fork accepts externally-authored code into its deployed build without reading it, on every drop — that is the fork's existing posture rather than a new exposure, but this record makes it policy, and it is written down at its true strength. ADR-0022 also records the known counter-example against itself: upstream's bin/.lefthookrc merges clean, is not in the ledger, changes which binary executes on every commit and push, and reintroduces filed bug #196. The scope ruling does not solve that, and the record says so explicitly rather than implying coverage it does not have.

… curation scoped to the contested surface

ADR-0021: upstream is adopted by merging the vendor drop; a decline is a row
in the divergence ledger, not an omitted commit. Cherry-pick-only rejected as
decline-by-default (67 commits / 796 files evaluated to protect 8);
hybrid-by-scope rejected as inexpressible (git has no per-path merge-base).
The load-bearing argument is recorded: the ledger plus `main` makes a decline
revisitable via `git diff main launchpad -- <path>`, so merging is not the
one-way door it appears to be.

ADR-0022: per-drop adjudication covers only the contested surface — files the
fork has modified that upstream also touched. The remaining 99% is adopted
wholesale by stated policy, because adjudicating all 67 commits degrades into
skimming, which is worse than an honest blanket policy since it looks like
review. Records the counter-example against itself: upstream's bin/.lefthookrc
merges clean, is not in the ledger, and reintroduces #196.

Closes #304
Refs #306 (scope half only; report shape, unit and model involvement stay open)

Signed-off-by: tucktuck101 <jeffreytaylorrobertson@gmail.com>

@serina-mcfall serina-mcfall left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent review — no blockers, one non-blocking issue filed

Reviewed in a fresh context. I am an agent and do not approve — posting as a comment so @serina-mcfall can.

The numeric foundation checks out. Both records rest on a measurement of the current backlog, and I reconstructed it at the commit count you measured:

$ c67=$(git rev-list f8692fa9b..upstream/main | tail -67 | head -1)
$ git diff --name-only f8692fa9b $c67 | wc -l
796
$ git rev-list --count f8692fa9b..$c67
67

796 files across 67 commits — exactly as stated. Running the same command at today's tip gives 912 across 80 commits, which is one day of upstream drift, not an error. Your record is the reason that's distinguishable: "Measured on 2026-08-21 against merge-base f8692fa9b (2026-08-17)" pins the measurement to a date and a base. The sibling research note on #374 omits its tip and a reviewer consequently mis-refuted a correct figure there — worth keeping this habit.

Verified independently:

  • ADR-0021 and ADR-0022 collide with nothing merged (highest merged is 0017) or in flight (#268→0018, #281→0019, #291→0020).
  • Every cross-referenced issue exists in the state claimed: #304 open, #306 open, #294/#301/#299/#307 open, #196 closed, #141 closed.
  • launchpad/scripts/adr_boundary_check.py and pr_body_check.py exist, as cited in Verification.
  • Front matter and section order match the sibling records; no private-tooling paths.
  • Provenance separates the human's call from the agent's recommendation in both records — and ADR-0022 records the agent's own counter-finding (the bin/.lefthookrc hazard) against the decision it supports. That's "state the bad honestly" actually honoured rather than formally present.

Non-blocker, filed as #386: neither launchpad/decisions/README.md nor launchpad/AGENTS.md says whether one PR may carry more than one ADR file. This PR is compliant on the documents as written — README constrains files per decision (1:1), AGENTS.md governs closing keywords per issue, and you use one Closes (#304) and one Refs (#306) for two separable decisions with distinct originating issues. But it's compliant by inference, and the next person will have to re-derive it. The issue asks for one sentence settling it.

Not verified: the bin/.lefthookrc claim about upstream setting LEFTHOOK_BIN to the pinned crashing lefthook 2.1.3 — I did not read that file at the upstream ref. And the off-repo conversation cited in Provenance is inherently outside what git can confirm; I verified the section names a human decider in the required shape, not that the conversation happened as described.

Ready for approval.

@benmitchell11 benmitchell11 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed per the ADR-recording checklist. Not approving — draft/comment only, per launchpad/AGENTS.md rule 1.

Checked: issues #304 and #306 in full (both zero comments; #306 has already been amended in-place with a "Partially decided" banner that accurately states what ADR-0022 settles and what stays open — good evidence the record and issue are kept in sync). Numbering against 0001–0017 (merged) and 0018/0019/0020 (reserved by open PRs #268/#281/#291 — no collision, and the PR body itself discloses the gap risk if those land out of order rather than hiding it). Cross-refs #294, #301, #307, #299, #196, #141 all resolve to what's cited.

Also noting: an independent agent review already posted on this PR (comment, not approval) reproduced the 796-files/67-commits measurement from a live git check, independently confirmed the numbering non-collision and cross-refs, and filed a non-blocking follow-up (#386) on whether one PR may carry more than one ADR file — README constrains one-file-per-decision but is silent on multi-ADR PRs, and this PR is compliant by inference rather than explicit rule. My own read agrees with that assessment; +1 to filing #386 separately rather than blocking on it here.

Matches the decided outcome. ADR-0021 (merge-based adoption, decline-by-ledger) and ADR-0022 (curation scoped to the contested surface, remainder adopted wholesale by stated policy) track #304 and #306's drafted option A and the 8-of-796 measurement each turns on. Splitting into two files is justified against README's one-file-per-decision rule and against the two issues closing differently (#304 outright, #306 only half).

Consequences is honest, notably so. ADR-0022 records a live counter-example against its own ruling — the bin/.lefthookrc/#196 hazard, which merges clean and isn't caught by the contested-surface scope — rather than omitting it. That's the "state the bad honestly" instruction actually followed, not just formally present.

Same non-blocking observation as the other two PRs in this batch: #304/#306 show no on-thread comment recording @tucktuck101's decision; Provenance's "decided in conversation" is asserted, not evidenced in either thread. Consistent with this repo's ADR-0017 precedent, so not treated as a deviation — just noting the pattern is now three-for-three across this reviewing batch.

No blocking issues found.

@serina-mcfall serina-mcfall left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Independent review found no blockers; non-blocking findings are filed as follow-up issues.

@serina-mcfall
serina-mcfall merged commit f93e805 into launchpad Aug 21, 2026
24 checks passed
@serina-mcfall
serina-mcfall deleted the docs/adr-0021-0022-adoption-and-curation-scope branch August 21, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

by:agent Filed or authored by an AI agent, not a human

Projects

None yet

Development

Successfully merging this pull request may close these issues.

adr: how the fork adopts upstream selectively and makes a decline durable — the vendor-branch dilemma

3 participants