From b0467f0ff97397f1fdf355e64553ac37314b842a Mon Sep 17 00:00:00 2001 From: Ada Date: Thu, 30 Jul 2026 11:25:01 -0400 Subject: [PATCH 1/2] docs: merge authority stays with the owner; record the unfinished test pruning Two things from the 2026-07-29 session that would otherwise be lost. Merge authority (OD-0020). The 2026-07-18 grant was real and was used once, on PR #163, but it lived only in an untracked memory file while CLAUDE.md and roster.json kept listing merging as ask-first. The estate held two contradictory answers for eleven days with nothing able to detect it. The owner resolved it by narrowing the grant: he retains merge authority while studio-2.0 is the staging target, because the risk is a correct-looking change landing on the wrong base. A per-task authorization expires with that task and is never read forward. He will revisit once studio-2.0 lands in main. Everything up to a reviewed, mergeable PR stays do-then-report, so this costs one message, not velocity. Unfinished test pruning, added to REMAINING_TASKS.md. About 40 low-value tests from the 2026-07-10 audit are still in the suite. The audit landed and most of its execution branches merged, but three did not, and they are on origin/studio2/phase-12.5-style rather than lost. Cherry-picking is not the way in: all three collide in the same three VoiceLab test files, which have moved on since. The entry says to redo the deletions against today's files and re-check each against R1-R4 first, since a test that was low-value in July may be load-bearing now. Co-Authored-By: Claude Opus 5 --- .claude/agents/roster.json | 3 +- ...s-with-the-owner-until-studio-2-0-lands.md | 39 +++++++++++++++++++ .claude/decisions/INDEX.md | 1 + CLAUDE.md | 2 +- design-docs/plans/REMAINING_TASKS.md | 16 ++++++++ 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 .claude/decisions/0020-merge-authority-stays-with-the-owner-until-studio-2-0-lands.md diff --git a/.claude/agents/roster.json b/.claude/agents/roster.json index 689360ee..3e34203b 100644 --- a/.claude/agents/roster.json +++ b/.claude/agents/roster.json @@ -192,7 +192,8 @@ "audio-quality verdicts", "information-architecture calls", "release-facing defaults", - "merging a PR, cutting a release, posting outside this repo", + "merging a PR (not delegated while studio-2.0 is the staging target; a per-task grant expires with that task, OD-0020)", + "cutting a release, posting outside this repo", "amending CLAUDE.md's binding sections or the mandate" ] } diff --git a/.claude/decisions/0020-merge-authority-stays-with-the-owner-until-studio-2-0-lands.md b/.claude/decisions/0020-merge-authority-stays-with-the-owner-until-studio-2-0-lands.md new file mode 100644 index 00000000..244e662b --- /dev/null +++ b/.claude/decisions/0020-merge-authority-stays-with-the-owner-until-studio-2-0-lands.md @@ -0,0 +1,39 @@ +# OD-0020: Merge authority stays with the owner while `studio-2.0` is the staging target +Status: accepted Date: 2026-07-29 +Scope: `CLAUDE.md` (ask-first list); `.claude/agents/roster.json` (`unowned_surfaces.owner_only`) + +Context: On 2026-07-18 the owner did grant merge authority in conversation ("I give you authority to +merge when you deem it ready"), and it was used once, on PR #163. That grant was recorded only in an +untracked memory file; `CLAUDE.md` and `roster.json` were never updated and continued to list merging as +ask-first, so the estate held two contradictory answers for eleven days. The 2026-07-29 retrofit surfaced +the contradiction and the owner resolved it by **narrowing the grant**: he authorized merging for one +specific task (landing PRs #174, #176, #177) and stated he retains the authority generally, because +`studio-2.0` is a temporary staging line and he is particular about nothing merging to the wrong branch +or being destructive while that is true. + +Decision: "Merging a PR, cutting a release, or posting anywhere outside this repo (issues/PR comments on +someone else's thread, external services)" remains on the ask-first list. Opening a PR, pushing a branch, +and choosing draft-versus-ready stay do-then-report; only the merge itself is withheld. A per-task +authorization covers that task and expires with it: it is never read forward into a standing grant. + +Consequences: Narrows the real 2026-07-18 grant rather than denying it happened. Two lessons sit inside +that: a grant recorded only in untracked memory produced a contradiction nothing could detect, which is +the case for writing rulings into tracked files (OD-0002's closeout discipline), and a conversational +grant can be narrowed later without either party having been wrong at the time. Blocks two specific +reflexes: citing a past one-off +authorization as ongoing permission, and merging a correct-looking change to the wrong base while +`studio-2.0` is standing in for `main`. Note the asymmetry this preserves: Ada can still get work all the +way to a reviewed, mergeable PR without asking, so the cost of the restriction is one message at the end, +not a slower pipeline. This is also the reason the change that records this ruling could not be +self-merged. + +**This expires by its own terms.** The owner stated he will loosen the mandate once `studio-2.0` merges +into `main`. That event, not a date, is the trigger to revisit — and revisiting means asking him, not +assuming the loosening is automatic. + +Disconfirming evidence: Merges are consistently routed to the owner as required, and the ask turns out to +be pure latency — every request is approved unread over a sustained period, with no merge ever redirected, +delayed, or rejected on inspection. That would show the gate is catching nothing the PR review already +caught. Note what does **not** count: an agent merging anyway is evidence about the agent, not the rule; +and a long quiet stretch with no wrong-base incident may be the rule working rather than the rule being +unnecessary. diff --git a/.claude/decisions/INDEX.md b/.claude/decisions/INDEX.md index 34138bc1..5f0a9ec4 100644 --- a/.claude/decisions/INDEX.md +++ b/.claude/decisions/INDEX.md @@ -28,3 +28,4 @@ the other. | [OD-0017](0017-orchestration-layer-edited-only-from-rooted-session.md) | accepted | CLAUDE.md orchestrator section; .claude/agents/ profiles; .claude/decisions/; roster.json; roster.html | This repo's orchestration layer is edited only from a session rooted in this repo | yes | — | | [OD-0018](0018-worktrees-are-not-the-default-and-are-removed-on-merge.md) | accepted | `CLAUDE.md` (Orchestrator identity & mandate); `.agent/rules/memory-queue.md`; agent dispatch decisions | Worktrees are not the default workflow, and a worktree is removed when its PR merges | yes | — | | [OD-0019](0019-a-functional-affordance-survives-a-redesign-only-if-defended.md) | accepted | `.claude/agents/junia-designer.md` (designer convictions); any redesign, visual migration, or screen-parity work | A functional affordance survives a redesign only if it is defended explicitly | yes | — | +| [OD-0020](0020-merge-authority-stays-with-the-owner-until-studio-2-0-lands.md) | accepted | `CLAUDE.md` (ask-first list); `.claude/agents/roster.json` (`unowned_surfaces.owner_only`) | Merge authority stays with the owner while `studio-2.0` is the staging target | yes | — | diff --git a/CLAUDE.md b/CLAUDE.md index 26bfca11..010b0b89 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -56,7 +56,7 @@ Do-then-report (no permission needed): Ask-first (unchanged): -- Merging a PR, cutting a release, or posting anywhere outside this repo (issues/PR comments on someone else's thread, external services). +- Merging a PR, cutting a release, or posting anywhere outside this repo (issues/PR comments on someone else's thread, external services). **Merge authority is the owner's and is not delegated (OD-0020)** — `studio-2.0` is a temporary staging line, and the risk being managed is a correct-looking change landing on the wrong base. A per-task authorization to merge covers that task only and expires with it; do NOT read a past one-off grant forward as standing permission. Take the work all the way to a reviewed, mergeable PR without asking, then hand over the merge. - Destructive or hard-to-reverse operations: data deletion, schema migrations, contract version bumps beyond the task at hand, reversing an ADR. - Amending CLAUDE.md's binding sections or this mandate itself. - Perceptual and product judgment: audio-quality verdicts, information-architecture changes, release-facing defaults — stage the evidence (A/B samples, screenshots, diffs) for the owner; never assert the verdict. diff --git a/design-docs/plans/REMAINING_TASKS.md b/design-docs/plans/REMAINING_TASKS.md index d0d864f5..fae9786f 100644 --- a/design-docs/plans/REMAINING_TASKS.md +++ b/design-docs/plans/REMAINING_TASKS.md @@ -116,6 +116,22 @@ observation is missing. spec→provenance citation map: [active/final_release/20_stale_docs_retirement.md](active/final_release/20_stale_docs_retirement.md)** (Section A already done; Section B is the repoint-then-delete remainder). +## Test-suite hygiene + +- [ ] **Finish the 2026-07-10 low-value test pruning (~40 tests still present).** The audit landed + (`active/final_release/audits/`) and most of its execution branches merged, but three never did: + Voices/VoiceLab (`751e6bd4`), backend DB (`7753b3fd`), and misc frontend pages (`f3493c36`), all + on `origin/studio2/phase-12.5-style`. The work is pushed and safe, just unmerged. + **Do not cherry-pick** — all three conflict in the same three VoiceLab test files + (`TestSection.test.tsx`, `VariantsSection.test.tsx`, `VoiceIconControls.test.tsx`), which have + moved on since. Redo the deletions against today's files instead, using each commit as the list + of what to remove and re-checking each against `testing-standards.md` R1–R4 before deleting + (a test that was low-value in July may have become load-bearing since). Rough cost: an hour. + Worth doing: the vitest suite leaks memory, so a smaller suite is a real win. + Evidence and per-branch verdicts: `.agent/reports/2026-07-29-reconcile-codeql-and-redundant.md`. +- [ ] Fix the hardcoded-style violation at `frontend/src/pages/Voices/.../ArchetypeQuickPick.tsx:242` + (found in passing during the 2026-07-29 reconciliation; unrelated to the branches assessed). + --- *When every item above clears and Stage 6's tag lands, this file should be empty — retire it and From 8aff9294d62e6d699a1922e55c0b68715137b110 Mon Sep 17 00:00:00 2001 From: Ada Date: Thu, 30 Jul 2026 11:27:07 -0400 Subject: [PATCH 2/2] lessons: squash-merge makes SHA and subject matching useless for reconciliation Reconciling 32 abandoned branches, a first pass matched commit subjects against studio-2.0's history and reported all 32 as unlanded. Nearly all had landed. rev-list --cherry-pick fails the same way, since a squash rewrites the patch-id of the whole branch into one commit, and reachability inflates the count because N branches sharing one squashed trunk each read as N distinct bodies of work. Only content answers it: read what the commit changed, then read those same files as they stand on origin/studio-2.0. Co-Authored-By: Claude Opus 5 --- .agent/lessons/INDEX.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.agent/lessons/INDEX.md b/.agent/lessons/INDEX.md index e5103e38..17dbd17b 100644 --- a/.agent/lessons/INDEX.md +++ b/.agent/lessons/INDEX.md @@ -1,5 +1,5 @@ # Lessons — always-on index -last-curated: 2026-07-17 +last-curated: 2026-07-29 These fire every session (auto-loaded via CLAUDE.md). Topic bodies live in `topics/` — read a shard only when its pointer matches. Cap: 10 always-on lessons; when full, demote the least-actionable into a shard rather than deleting it. @@ -10,5 +10,7 @@ These fire every session (auto-loaded via CLAUDE.md). Topic bodies live in `topi - `COMPLETED_WORK.md`'s "shipped" is not owner-verified-complete — never write a public wiki changelog entry or delete a source plan on its word alone (2026-07-18) — during the release doc reduction, COMPLETED_WORK listed HuggingFace voice, AI casting, and the recording-cue expansion as "shipped/live/all shipped." Acting on that, I wrote wiki changelog entries for two and marked their plans deletable. Owner review corrected all three: HF is untested/needs sign-off, AI casting is placeholder/future in the app, recording-cue awaits the owner's portrait-image generation. The changelog entries were reverted; no plan had been deleted (the ledger gate held). **Apply:** treat "shipped" in a summary doc as a claim to verify, not a fact. Before writing the history-of-record (wiki changelog) or deleting a plan, confirm completion against on-disk reality AND owner sign-off — "code + endpoints landed" ≠ "feature complete." A feature marked future/placeholder in the app, or awaiting an owner action, is not a changelog entry and its plan stays. The consolidation ledger (`design-docs/plans/active/final_release/21_*`) is the gate that made this recoverable — keep deletions gated on it. +- `studio-2.0` squash-merges, so a branch's commit SHAs and subjects NEVER appear in its history even when the work fully landed (2026-07-29) — reconciling 32 abandoned branches, a first pass matched commit subjects against `git log origin/studio-2.0` and reported all 32 as unlanded, which was false for nearly all of them; `git rev-list --cherry-pick` was equally useless, because a squash rewrites the patch-id of the whole branch into one commit. Reachability (`--contains`, `merge-base --is-ancestor`) is also unreliable for the same reason, and inflates the count: N branches holding one shared squashed trunk each read as N distinct bodies of unlanded work. **Apply:** to answer "did this branch land", read what the commit changed and then read the CURRENT content of those same files on `origin/studio-2.0` — for a deletion, check the deleted file/test name is also absent there; for an edit, compare the file's content. Only content answers it. Corollary for the reverse direction: a branch whose files no longer exist on `studio-2.0` at all is usually obsolete-by-restructure, not unlanded. Worked verdicts for 32 branches: `.agent/reports/2026-07-29-reconcile-*.md`. + ## Topic pointers (read on match)