Skip to content

Pre-release: simplified README, blind-UAT'd docs, eleven bugs found and fixed - #48

Merged
jordonpeterson merged 13 commits into
mainfrom
claude/pre-release-review-testing-qlzcyj
Aug 23, 2026
Merged

Pre-release: simplified README, blind-UAT'd docs, eleven bugs found and fixed#48
jordonpeterson merged 13 commits into
mainfrom
claude/pre-release-review-testing-qlzcyj

Conversation

@jordonpeterson

@jordonpeterson jordonpeterson commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Pre-release deep dive in three phases: README simplification with verified accuracy, a blind-UAT acceptance loop on the docs, and an adversarial bug hunt whose eleven confirmed findings were first encoded as failing e2e tests and are now all fixed — each test flipped into a regression guard. CI should be fully green.

Phase 1 — README (commits 1, 4, 5, 8)

  • README 528 → ~200 lines: a front door (pitch, install, routing table, 60-second tour, core concepts, pointers), with the worked walkthroughs moved to the new docs/GUIDE.md (<200 lines, per the repo's own rule). ~60% of the old README duplicated REFERENCE/LINTING/FLEET verbatim.
  • Every command/output/exit-code in the old README was replayed against a fresh build first — zero discrepancies — so the rewrite reuses proven transcripts.
  • Linked the orphaned docs/CONCEPTS.md, SECURITY.md, CHANGELOG.md; documented the R-33 list form and the except clause; fixed a dead anchor; added lint --policy to the synopsis.

Phase 2 — Blind-UAT acceptance loop (commits 4–5)

A sandbox with only docs + binary + fixture repos; fresh "blind" subagents complete increasingly nasty CODEOWNERS change requests from the docs alone, graded by script against resolved ownership. Round 1: 9/9 with logged friction → docs iteration (runnable escape hatches in "When it refuses", snapshot/verify hygiene, [] vs null, a REFERENCE snapshot/verify section). Round 2, harder 14-task suite, fresh agent: 14/14. Acceptance criterion met.

Phase 3 — Eleven bugs: encoded as failing tests, then fixed (commits 2–3, 6–13)

Every bug was reproduced, minimized, and pinned by a failing e2e test before any fix; fixes were built by parallel subagents with disjoint file ownership, then the combined diff went through a code-review pass and an adversarial verification agent whose findings were fixed in turn.

Fixed Bug
sync.go/cli.go plan/apply skipped the repo-root guard — wrote a CODEOWNERS GitHub never reads, reported success
co-own.sh Un-anchored single-segment scopes: op and its verify proof ran broader than typed
pattern.go \# patterns written and "proven" although GitHub honors no such escape (leading position rejected; oracle-verified, fuzz 0 mismatches)
cli.go Symlinked CODEOWNERS — file or any parent directory — written through silently; now refused at exit 2 naming the component
cli.go audit --format json printed "audit clean" after the JSON, breaking jq on healthy repos
cli.go Positional args silently dropped with every flag after them; now exit 3 on every verb
lint Tree-provably-dead rules unremovable offline; new tree-only mode for --remove-stale-paths (engages only when neither credential is given; owner checks skipped, disclosed, never degraded silently; invalid lines still reported at exit 4)
sync.go --end-of-options echoed into the S-7 refusal; detached-HEAD label unreachable
sync.go Uncleaned --file spellings drew a false "governs nothing" warning into records and PR bodies
cli.go audit silently accepted unknown --format; now exit 3 like every other verb
plan.go set_owners authored a shadowed duplicate without disclosing it; the R-7 warning now fires in the authoring run

Review-pass findings also fixed (commits 11–13): restored default: refusal arms in both zero-match switches (unknown values had become silent no-ops); owner comparisons in co-own.sh now fold @handle case per R-38 (emails stay byte-exact); the R-25 ceiling refusal names only ops that changed paths; every record-less sync exit-3 emits the documented "no record was written" note; the stale-comment rename warning checks the leading token boundary (no more false hits on someone@old-team); policy-aware offline-lint refusal wording; a mixed-case dead owner's empty Reason; five stale doc lines updated to the new lint contract.

Deliberately deferred (follow-up material)

  • Perf: ops.StaticConflict is O(n²) with the expensive containment check first (a 1MB policy under the documented cap extrapolates to hours — swap commutes ahead of scopeCoverage); commuteOnEveryOwnerSet enumerates 2^n owner subsets on large R-33 lists in the declare path.
  • verify renders tree-membership changes as (unowned) → (unowned); UTF-8 BOM makes the first rule silently dead; audit of user-owned (non-org) repos can never conclude; A-7 prints Go-style line lists; refusal text prints twice (error + summary echo); the difftest generator's alphabet contains no #, so the \# change is covered by unit tests and a hand harness, not the fuzz.
  • Release hygiene: consider moving docs/PROPOSAL-*.md out of user-facing docs.

Test suite: full go test ./... green, differential fuzz 0 mismatches (multiple seeds), make docs clean, blind-UAT harness available in session scratchpad for re-running against future changes.


🤖 Generated with Claude Code

https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K

claude added 2 commits August 22, 2026 18:17
The README duplicated large parts of REFERENCE.md, LINTING.md and FLEET.md,
often verbatim, and at 528 lines broke the project's own <200-line rule.
It is now a ~190-line front door: pitch, install, routing table, a 60-second
tour, core concepts, and one-paragraph pointers into the docs. The worked
examples (bootstrap, modify, plan/apply review, refusals) move to the new
docs/GUIDE.md, kept under 200 lines.

Also: link the orphaned docs/CONCEPTS.md, SECURITY.md and CHANGELOG.md from
the doc map, document add_owner/remove_owner's bracketed-list form (R-33) in
the ops table, mention the except clause, fix the dead #audit---lint anchor
in REFERENCE.md, and add lint's --policy flag to its synopsis.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
Each test states behavior the tool should have and currently does not, so
each FAILS until its bug is fixed and then becomes the regression guard:

- plan/apply skip sync's repo-root guard and write a CODEOWNERS GitHub
  never reads, reporting success (the "dead on arrival" outcome)
- a \#-escaped pattern is written and "proven" although S-6 says GitHub
  honors no such escape, so the rule is dead on GitHub
- a symlinked .github/CODEOWNERS inside the clone is written through
  silently, though the docs state GitHub does not follow it
- the S-7 branch-mismatch refusal embeds raw "--end-of-options\n" from
  git rev-parse in its error text
- --file ./.github/CODEOWNERS (uncleaned spelling) draws a false
  "governs nothing" warning that flows into records and summaries
- set_owners authors a shadowed duplicate rule without disclosing it;
  the R-7 warning only fires on the next run
- audit --format json prints "audit clean" after the JSON on the clean
  path, breaking every jq pipe exactly on healthy repos
- positional arguments are silently dropped along with every flag after
  them, so "audit <repo> --checks a999" audits the cwd at exit 0
- audit accepts an unknown --format and silently falls back to text;
  sync, check and lint all refuse at exit 3
- co-own.sh un-anchors single-segment scopes (/docs/ becomes docs), so
  the op and its verify both run broader than the operator typed:
  out-of-scope paths change owners and verify reports all-within-scope

docs/BEHAVIOR.md regenerated (make docs) for the new test doc comments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
Copilot AI lite review requested due to automatic review settings August 22, 2026 18:18

Copilot AI 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.

🟡 Changes recommended

The newly added prerelease tests are designed to fail and will keep the default test suite/CI red unless they’re gated (e.g., build tags or skipped by default).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR prepares for a pre-release by restructuring the top-level documentation (moving worked examples into a new guide) and adding “known bug” e2e tests that encode currently failing behaviors as executable specs.

Changes:

  • Simplifies README.md into a shorter “front door” and updates the doc map to point readers to dedicated guides/reference docs.
  • Adds docs/GUIDE.md with worked end-to-end walkthroughs and refreshes generated docs/BEHAVIOR.md.
  • Introduces new prerelease “known bug” e2e test files for internal/cli and tools/fleet.
File summaries
File Description
README.md Slimmed/reshaped README with updated pointers and a short “tour” section.
docs/GUIDE.md New worked-examples guide extracted from the README.
docs/REFERENCE.md Fixes/updates references in command synopsis and anchor/linking around lint.
docs/BEHAVIOR.md Regenerated behavior documentation to include the new prerelease test docs.
internal/cli/prerelease_bugs_test.go Adds prerelease failing e2e tests capturing known CLI bugs.
tools/fleet/prerelease_bugs_test.go Adds prerelease failing e2e test capturing a known co-own.sh scope bug.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/cli/prerelease_bugs_test.go Outdated
Comment thread tools/fleet/prerelease_bugs_test.go Outdated
claude added 11 commits August 22, 2026 19:03
…le gap

A blind subagent completed a 9-task CODEOWNERS-editing suite using only the
docs (9/9 verified by independent grading), but its log named real friction:

- GUIDE's "When it refuses" gave advice with no runnable command; the two
  working escape hatches (narrow the scope spelling, or carve out paths with
  an except clause) are now shown with ops, and except.md is linked from the
  section where a stuck user actually stands.
- snapshot reads the committed file and verify counts tree membership as
  change; the reviewing section now states both hygiene rules, and
  REFERENCE.md gains a snapshot-and-verify section (exit codes, --scope,
  [] vs null in the ownership map).
- The [] vs null semantics are stated where snapshot output first appears in
  the README, along with per-command --help discoverability.
- REFERENCE's Operations table now covers the R-33 bracketed-list form.
- LINTING.md states plainly that offline dead-rule removal is unsupported.

That last one is also a product gap, not just a docs one: a rule audit proves
dead from the tree alone (A-4/A-5, no API involved) cannot be removed without
a GitHub token — lint refuses the whole run at exit 5 citing owner-existence
rules that don't apply to --remove-stale-paths. New failing e2e test
TestKnownBug_OfflineStaleRuleRemovalReportable documents it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
A fresh blind agent completed all 14 CODEOWNERS-editing tasks (basic through
adversarial) from the docs alone — 14/14 under independent grading. Its two
remaining complaints were both one-line gaps: scope spellings with spaces
(backslash escape) appeared only in except.md's grammar, and the README tour
never said snapshot reads the committed file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
…ates (R-7)

Two of the eleven pre-release findings, turning their formerly-failing e2e
tests green:

- pattern.Compile now rejects a pattern beginning with \#, mirroring the
  existing ! treatment: GitHub honors no such escape, so a written \#-rule
  is a comment there and the tool's proven-tree claim would be false in the
  one place it matters. Only the leading position is rejected — a mid-pattern
  hash needs no escape and keeps its oracle-compatible literal meaning. A
  pre-existing \# line degrades through the established invalid-line path
  (skipped in resolution, reported by A-8). Differential fuzz vs the hmarr
  oracle: 0 mismatches on two seeds.

- synthSet now warns, in the same run, when its inserted rule shadows an
  earlier byte-equal pattern — previously the R-7 duplicate warning only
  fired on the NEXT run, leaving the run that authored the dead line silent.
  Written bytes are unchanged (R-1); only the disclosure is new.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
The script stripped the anchoring slash from the typed scope, so a
single-segment /docs/ became the unanchored docs — matching at any depth —
and BOTH the op it ran and the verify --scope that was supposed to prove the
edit used that broadened spelling: out-of-scope paths changed owners and the
proof blessed it. The op and verify now receive the scope exactly as typed
(the tool's own matcher supplies real anchoring semantics); the branch name
and awk line-match keep their stripped spelling; the jq state logic gains an
anchored/unanchored flag so its decisions agree with what the op will do.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
- plan and apply now run the same checkRepoRoot guard as sync: a --repo
  below the repository root writes a CODEOWNERS GitHub never reads, so it is
  refused at exit 2 before any artifact is written.
- audit --format json emits exactly one JSON document; the 'audit clean'
  verdict line is text-mode only.
- Every verb rejects leftover positional arguments at exit 3, naming the
  stray argument — Go's flag parser silently dropped them and every flag
  after them.
- audit validates --format like sync/check/lint do; never a silent fallback
  to text.
- headLabel no longer passes --end-of-options to rev-parse (which echoes it
  as output in filter mode), fixing the garbled S-7 refusal and making the
  detached-HEAD bare-SHA label reachable.
- The S-8 location check classifies the cleaned --file spelling, so
  ./.github/CODEOWNERS no longer draws a false 'governs nothing' warning in
  output, records, and summaries.
- A symlinked write target is refused at exit 2 in sync, apply, and lint:
  GitHub does not follow a symlinked CODEOWNERS, so writing through one is
  the 'applied, dead on arrival' outcome the containment guard exists to
  prevent. Symlinks elsewhere in the repo stay irrelevant.

Turns six formerly-failing KnownBug e2e tests green; adds nine hardening
tests in prerelease_fixes_test.go.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
A rule the offline audit proves dead from the tree alone (A-4/A-5) could not
be repaired without a GitHub token: lint refused the whole run at exit 5
citing R-12, whose rationale — owner existence is an API fact — does not
apply to stale paths, a git-tree fact. The only offline remedy was the hand
edit the tool exists to prevent.

Offline (no token / no --github-repo) with --remove-stale-paths now runs
only the dead-rule removal stage against the tree at --branch: owner checks
are skipped entirely — never degraded — and the skip is disclosed in text
output and as owner_checks_skipped in JSON. The A-5 case-only miss stays
spared exactly as online (a typo, not a dead rule; exit 4). Offline without
--remove-stale-paths keeps the exit-5 refusal, now naming the escape hatch.
R-12 fail-closed behavior for owner repairs is untouched: no owner is looked
up, repaired, or removed offline, and the Verifier is never constructed.

Also carries the symlinked-target refusal wiring in the lint verb from the
companion CLI commit. Turns the last KnownBug e2e test green; adds twelve
offline-mode tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
All eleven formerly-failing tests now pass; the KnownBug_ prefix and the
expected-to-fail headers are gone, the finding descriptions stay as the
record of what each test guards. docs/BEHAVIOR.md regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
Review findings from the fix-verification pass:

- The OnZeroMatch switch lost its default arm in the except work, so an
  unrecognized value on a zero-match scope fell through to a silent no-op
  reported as unchanged/proven-tree. Restored as an exit-3 InvalidError
  naming the value; the sibling OnExceptZeroMatch switch had the milder form
  of the same hole (typos swallowed into require behavior at the wrong exit
  class) and gets the same treatment.

- co-own.sh compared owners byte-exactly while the tool folds @handle case
  everywhere (R-38), so a case-variant spelling landed the repo in the wrong
  lane. Every owner comparison in the script's jq and awk now folds
  @-prefixed owners and leaves email owners byte-exact, mirroring
  ops.FoldOwner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
- refuseSymlinkedTarget now Lstats every component of the write path below
  the repo root, not just the final one: git records a symlinked directory
  as a link blob, so .github -> elsewhere made .github/CODEOWNERS a path
  GitHub's tree never contains while sync/apply/lint wrote through it and
  reported applied. The refusal names the offending component and its
  target; symlinks off the write path stay irrelevant.
- The R-25 ceiling refusal no longer names already-satisfied ops as 'the
  op(s) behind the number' — only ops that actually change paths.
- Every record-less sync exit-3 now emits the documented 'no record was
  written' stderr note when --out/--summary-out was asked for, through one
  choke point instead of two special cases.
- The stale-comment warning checks the leading token boundary too, so a
  handle embedded in a longer token (someone@old-team) no longer draws a
  false 'a comment still names' warning on rename.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
Review findings against the new offline tree-only mode:

- The mode now engages only when NEITHER a token nor --github-repo was
  given. A run that supplied either one asked for the credentialed lint and
  refuses at exit 5 naming exactly the missing half — never a silent
  degradation — and a malformed --github-repo is exit 3 whether or not a
  token is present. The disclosure sentence is now true by construction.
- The exit-5 refusal's escape hatch is policy-aware: under --policy it
  names the remove_stale_paths field in the lint block instead of the
  exit-3-banned flag (the R-36b double-refusal trap).
- Offline runs report invalid lines instead of exiting 0 over them: a
  syntactically broken line is a tree fact GitHub is already skipping, so
  it is needs-human at exit 4 with a reason naming the credentialed run
  that can repair it. No repair happens offline.
- Pre-existing one-token bug: remove-dead-owner actions read the reason map
  with the unfolded spelling, so a mixed-case dead owner got Reason:.

Docs conditioned to match (LINTING.md flag/exit tables and error walk-
through, REFERENCE.md required-flags and exit-5 rows, owner_checks_skipped
in the JSON contract); BEHAVIOR.md regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg69i7e9Z96dPzrW2Zfq3K
@jordonpeterson jordonpeterson changed the title Pre-release review: simplified README + failing e2e tests for ten bugs Pre-release: simplified README, blind-UAT'd docs, eleven bugs found and fixed Aug 22, 2026
@jordonpeterson
jordonpeterson merged commit f4294ee into main Aug 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants