Skip to content

fix(dev-team): address session-review findings #2103-#2111 - #2116

Merged
bdfinst merged 11 commits into
mainfrom
claude/dev-team-setup-ly5u4w
Sep 4, 2026
Merged

fix(dev-team): address session-review findings #2103-#2111#2116
bdfinst merged 11 commits into
mainfrom
claude/dev-team-setup-ly5u4w

Conversation

@bdfinst

@bdfinst bdfinst commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Summary

Nine issues filed from the 2026-09-04 session-review digest, addressed as one batch (each on its own investigation, several with an unexpected root cause once traced):

Test Plan

Closes #2103
Closes #2104
Closes #2105
Closes #2106
Closes #2107
Closes #2108
Closes #2109
Closes #2110
Closes #2111

🤖 Generated with Claude Code


Generated by Claude Code

claude and others added 11 commits September 4, 2026 14:05
…published skills/ dir

scripts/assemble-docs.sh copies only each plugin's docs/ directory into the
published MkDocs site — never skills/ or commands/. build_skills_index.py's
generated "File" column linked with a relative ../skills/<name>/SKILL.md
path, which resolves in a repo checkout (and passes the repo-tree-scoped
lychee link check) but 404s once deployed, since that directory was never
copied into the assembled site.

Link to the file's GitHub source instead, which resolves both in a checkout
and on the live site. Regenerated the three affected catalogs (dev-team,
security-assessment, marketplace-dev) and added a regression test asserting
every generated link points at github.com rather than a relative path.

Fixes #2103

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
…ly diffs

change_shape.py's runtime-surface gate correctly treats functional
Claude-config markdown (agents/, skills/, knowledge/, .claude/ paths) as
runtime surface, so performance-review/correctness-review still run against
it. But security-review, domain-review, test-review, and performance-review
review a code-level property no markdown file can exhibit, functional or
not — an injection vulnerability, a domain-boundary leak, a test-coverage
gap, or an N+1 query. Dispatching all four against a single-file
skill-markdown diff produced elaborate findings framed as security/domain/
test/performance issues that were really prose/spec-consistency nitpicks.

Add a new, independent `is_prose_only` signal (every changed file is
.md/.mdx, no functional-config carve-out) and PROSE_ONLY_SKIP_LENSES
(security-review, domain-review, test-review, performance-review). Each of
those four agents' own `## Skip` clause already self-reports skip on a
documentation-only target, so this pays for what would otherwise be a
self-reported skip or an ungrounded finding. correctness-review, doc-review,
spec-compliance-review, structure-review, naming-review, and arch-review
stay in the roster.

Deliberately narrower than select_lenses.py's own
NON_EXECUTABLE_SKIP_ELIGIBLE allowlist, which considered and rejected
filtering security-review/domain-review for its broader "non-executable"
category (docs and config/lockfiles/assets) — that gate never widens past
.md/.mdx, so the rejection's rationale (security-review's credential-scanning
duty over config files) doesn't apply here.

Fixes #2104

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
… regexes

Both assertions in tests/skills/test_setup_yes_flag.py greeped the whole
collapsed SKILL.md rather than the specific bullet they claimed to verify,
so each could pass without checking its real target text:

- test_setup_never_guesses_stack_under_yes grepped the whole document for
  "never guess a stack". The intended target (the Conservative-bucket
  "Unrecognized / ambiguous stack" bullet) actually reads "never guesses a
  toolchain" — no match. The only text that matched was an unrelated Step 6
  mutation-tooling clause, so the test passed off the wrong occurrence.
- test_project_init_yes_auto_confirms_plan_and_keyless_pair's first
  assertion's `three-column plan.*proceed` alternative, applied against the
  whole document collapsed to one line, could span from the Step 3 bullet to
  any later, unrelated "proceed" occurrence — several exist — making that
  branch nearly always true regardless of doc content.

Bound both to their specific target bullet via section_outside_code(),
mirroring the pattern already used elsewhere in this file, and fixed the
first assertion's wording to match what the bullet actually says.

Fixes #2105

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
…on path

Diagnosis: the session digest's gate.gate_ran_absent: 68/68 (100%) finding
does NOT mean the pre-commit gate never runs. Two things checked out clean:

- hooks/pre_commit_review.py is documented as an intentional no-op (#1886):
  the review-corroboration gate deliberately moved from `git commit` to
  `gh pr create` time (hooks/pre_pr_review.py, correctly registered in
  settings.json). Its absence from settings.json is by design, not a defect.
- .husky/pre-commit (the real git-native gate #2037 instruments) correctly
  emits a `gate-ran` boundary event at every exit point, verified live in
  this session: three ordinary commits each produced a correlated
  `gate-ran-allow` record in .claude/metrics/boundary-events.jsonl.

The actual bug: `cmd_sync` (session_report.py --sync-out, the path that
durably archives onto .claude/metrics/session-digest.jsonl at every
SessionStart and feeds /session-review's cross-session digest) called
extract_maintainer() without its `boundary_events_path` argument. That
parameter has no internal default — `_read_gate_ran_events(None)` returns
`[]` unconditionally — so every non-bypassed commit attempt in every synced
session classified `gate_ran_absent`, regardless of whether the gate
actually ran. `cmd_sync` already derives the session's own
`.claude/metrics/boundary-events.jsonl` path two lines below (for
plugin_version resolution, #2018); thread that same path through to the
gate correlation too.

Added two regression tests reproducing the exact symptom against `--sync-out`
(one proving a real gate-ran-allow event now correlates instead of reading
absent, one proving a session with no matching event still correctly reports
absent) — confirmed the first fails against the pre-fix code.

Fixes #2106

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
Session digest found /build and software-engineer carry the highest
correction rates in the plugin (correction_rate_by_skill.build: 0.8689 vs.
the next highest at 0.052; correction_rate_by_agent.software-engineer:
1.05 — more corrections than dispatches).

quality-gate-pipeline's Phase 2 already states the right bar (tests, build,
lint as "Required Evidence" before any completion claim), but nothing in
/build's own per-step cadence made it mandatory at the moment a checkbox
actually flips. The per-step mini-cycle hard-gates on tests (TEST phase,
sub-step 2) and re-runs them after REFACTOR (sub-step 3) — but REFACTOR can
rename/restructure code in ways a test suite alone won't catch, and neither
lint nor type-check were ever mentioned in the per-step cycle at all, so a
step could reach "Mark step done" (sub-step 5) with a stale or unclean lint
state that only surfaces later, in Step 6's backstop review.

- build/SKILL.md sub-step 3 (REFACTOR): require lint/type-check tools,
  when the project has them, to run and pass alongside the re-run tests.
- build/SKILL.md sub-step 5 (Mark step done): require that evidence be
  fresh from this session before flipping any checkbox — not recalled,
  not assumed.
- agents/software-engineer.md: added a hard Constraints bullet making
  quality-gate-pipeline Phase 2's evidence requirement mandatory before
  signaling any step or task done, including outside /build's own cadence.

Fixes #2107

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
… entry

Investigated the two churn-heaviest files from the session digest:

- testimprove_phase_scope_guard.py does not exist anywhere in this repo's
  git history (git log --all finds nothing, on any name variant). Given
  this repo's recent Wave 3/4 script-consolidation PRs (#2083-#2088)
  renamed/merged a large slice of the telemetry scripting tree, the
  digest's filename most likely refers to something renamed away since —
  or the digest itself (an AI-authored report) mis-transcribed a real path.
  Nothing to investigate further against a file that was never real.

- bash_failure_taxonomy.py's churn was three legitimate review rounds
  fixing genuinely hard compound-shell-command edge cases (#2085's PR
  history), each already closed with its own regression test at the time.
  The module also carries an explicit, deliberate "self-contained by
  design (post plan-review-design)" policy — it intentionally keeps its
  own shell-segmentation logic rather than importing session_log's, for a
  stated privacy-boundary reason. A "consolidate duplicate parsers" check
  would contradict that already-reasoned decision, so none was added here.

That same PR's review history did surface one real, mechanically-checkable,
twice-reported defect that was never ratcheted: round 2 fixed
churn_recurrence.py's render_text() reading report["window"] via a bare
index (KeyError for a caller rendering rank_all_files()'s own output,
which never sets that key); round 3's very next review pass found the
IDENTICAL bug in churn_coupling_report.py's sibling render_text(). Two
occurrences of the same fact is this repo's own trigger to convert it into
a repo_invariants.py CHECKS entry — done here, one round late.

Fixes #2108

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
…lls into software-engineer

Session digest found software-engineer dispatches carrying far more context
per dispatch than any other agent type (context_per_dispatch: 13,072,914 vs.
fork: 3,396,501 / general-purpose: 6,579,396 / quality-reviewer: 6,405,061),
without a matching accuracy payoff (only 20 dispatches, highest correction
rate in the digest).

Dispatched token-efficiency-review to investigate. Finding: software-engineer's
`skills:` frontmatter (ADR 0028: every agent with a `## Skills` section must
preload every listed skill on every dispatch, unconditionally) declared nine
skills, five of which the agent's own body already documents as
conditional — "invoke when structuring new services" (hexagonal-architecture),
"invoke when modeling business domains" (domain-driven-design), "invoke when
implementing APIs" (api-design), "invoke when modifying ... legacy code"
(legacy-code), "invoke when assessing ... mutation" (mutation-testing). These
five total ~68KB (~17K tokens) of SKILL.md prose loaded as a per-dispatch
baseline regardless of whether the step ever touches any of them — and
because a subagent's context gets cache-read again on every subsequent turn,
this baseline compounds across a many-turn implementation dispatch.

ADR 0028's gate only requires every FRONTMATTER-declared name to trace back
to the `## Skills` section text, not the reverse — so removing these five
from `skills:` while keeping their "invoke when X" bullets in the section
(now split into a Preloaded/On-demand grouping) satisfies the gate and stays
fully documented and invocable, just no longer force-loaded on every
dispatch. quality-gate-pipeline, test-driven-development, systematic-debugging,
and code-review stay preloaded — quality-gate-pipeline in particular backs
#2107's hard self-verification constraint and must not be dropped.

Fixes #2109

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
Session digest found a large gap between two rework counters
(retried_bash_commands: 3947 vs. repeated_verify_runs: 1) with no per-skill/
per-agent breakdown to trace the volume to a specific stop-condition gap.

signals.track_bash's retry detection moves from a post-loop histogram sum
(sum(n-1 for n>1) over a thread's whole bash-command Counter, computed
after all records in a transcript file were processed) to live, per-event
detection: each retry is now attributed, at the moment it's detected, to
whichever skill/agent is the thread's current sticky active pointer (the
same pointer accumulate_skill_agent_signals maintains and the existing
correction_by_skill/by_agent signal already attributes against) -- falling
back to "unattributed" when neither is set. The scalar retried_bash_commands
total is now derived as the sum of the by_skill breakdown, never a second
independent computation, matching the lesson from #2108's window-key bug.

Threaded the new retried_bash_commands_by_skill/by_agent fields through both
extractors end to end: extract_maintainer, extract_downstream/combine,
sync_record (the --sync-out per-session record durably archived at every
SessionStart), and rollup (the cross-session aggregate /session-review
reads) -- including the peer-input sanitization pass (_normalize_name_dicts)
a synced record's name-bearing dicts already get, extended to cover these
two new fields against the same hostile-key threat model as accuracy.by_skill/
by_agent.

Fixes #2110

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
… token count

#2109's software-engineer.md edit changed its measured token size; the
hand-maintained ~Tokens column in agent-registry.md is a real, checked
figure (scripts/measure_tokens.py --verify, run by the pre-push gate) and
was left stale, flagged DEVIATED at 13.7% drift (2,122 declared vs. 2,458
measured). Refreshed to the current measured value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URnco7Z5bKfKBMdNiZGQL4
@bdfinst
bdfinst enabled auto-merge (squash) September 4, 2026 15:54
@bdfinst
bdfinst merged commit b6514a7 into main Sep 4, 2026
15 checks passed
@bdfinst
bdfinst deleted the claude/dev-team-setup-ly5u4w branch September 4, 2026 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment