Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude/metrics/config-changelog.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@
{"timestamp": "2026-09-17T15:36:16.556298+00:00", "type": "approval", "proposed": "acceptance-criteria set: plans/measure-rereview-duplication.md (issue #2165)", "evidence_shown": "plans/measure-rereview-duplication.md", "risks_surfaced": ["AC6: cross-reference to step 1.4 checkpoint list not inlined", "AC8: additive-alias pattern not defined in AC text"]}
{"timestamp": "2026-09-21T18:49:13Z", "type": "approval", "proposed": "Approve plan for Agent lifecycle improvements (#2172 batch: #2187-#2190)", "evidence_shown": "plans/2172-agent-lifecycle-improvements.md", "risks_surfaced": ["Strategic critic recommended splitting into up to 3 PRs; acknowledged, not adopted (user pre-decided single-batch)", "Slice 2 malformed-hand-back scenario is provisional pending Step 2.1a transcript-shape confirmation", "Slice 4 JS/TS fast-check test may need network-exempt fallback if vendoring proves impractical"], "description": "Auto-approved (non-interactive) - no usable TTY in this remote session"}
{"timestamp": "2026-09-21T18:51:16Z", "type": "approval", "proposed": "Acceptance-criteria gate for plans/2172-agent-lifecycle-improvements.md", "evidence_shown": "plans/2172-agent-lifecycle-improvements.md", "risks_surfaced": ["Step 1.4 latency check has no quantitative SLA threshold", "Step 1.2 missing idempotent-double-fire test case", "Step 2.1a conditional AC pass/fail ambiguity if no hand-back signal found", "Step 2.1b missing invalid-JSON (not just unreadable) transcript test", "Step 3.1 claim-extraction heuristics under-specified with only 2 of 5 pinned", "Step 3.2 missing malformed-but-parseable WebFetch response case", "Step 3.3 doc-review integration test is structural-only, not behavioral", "Step 4.1 property-derivation edge cases (cross-module pair, ambiguous invariant) untested", "Step 4.2 missing language-specific runtime-failure cases (Hypothesis/fast-check install failure)", "Step 4.3 vendoring-impractical threshold undefined"], "description": "Acceptance-criteria gate auto-passed with 10 flagged (0 blocker, 2 warning, 8 suggestion/minor) criterion findings (non-interactive) - no human gate. Trigger: --yes flag. Findings will be resolved as implementation-time decisions during Step 4, per the plan own assumptions-recording convention."}
{"ts": "2026-09-22T14:33:36Z", "type": "approval", "proposed": "Approve plan for #2166+#2171 verdict-ledger writer batch (part of #2164)", "evidence_shown": "plans/2164-verdict-ledger-writer.md", "risks_surfaced": ["Bash write-shape detection is a heuristic, not a sandbox", "override-audit.jsonl/config-changelog.jsonl remain unguarded (Decision 5 scope-narrowing)", "Step 2.1 marker/Step 2.3 parser format drift risk", "No consumer exists yet for review-verdicts.jsonl until #2167", "plan-review-strategic suggested splitting into two PRs (not adopted)", "Decision 4a: verdict trust boundary relies on the orchestrating session's own declared scope marker, not independently re-verified"], "description": "Auto-approved (non-interactive, --yes via /ship)"}
{"ts": "2026-09-22T14:37:03Z", "type": "approval", "proposed": "Acceptance criteria set for #2166+#2171 verdict-ledger batch (part of #2164)", "evidence_shown": "plans/2164-verdict-ledger-writer.md", "risks_surfaced": [], "description": "spec-compliance-review criteria-verification pass: all 10 criteria PASS, no flags"}
28 changes: 12 additions & 16 deletions plugins/dev-team/hooks/agent_dispatch_ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,7 @@
sys.path.insert(0, str(_LIB_DIR))

from boundary_events import emit_boundary_event as _emit_boundary_event
from review_agent_registry import (
default_agents_dir,
read_registered_review_agent_names,
strip_plugin_prefix,
)
from review_agent_registry import is_registered_review_lens, strip_plugin_prefix
from review_gate_hash import (
EMPTY_DIGEST,
branch_diff_gate_hash,
Expand Down Expand Up @@ -124,24 +120,24 @@ def main() -> int:
if not isinstance(subagent_type, str) or not subagent_type:
return 0

# Normalize the plugin-qualified dispatch form ("dev-team:doc-review") to
# the bare name the registry's closed set uses, so the plugin's normal,
# installed invocation form is recognized identically to a bare-named one.
subagent_type = strip_plugin_prefix(subagent_type)

# #1904 item 1: `read_registered_review_agent_names()` returns `None` on
# a registry read failure, distinct from a genuine `frozenset()` — but
# this is the WRITE/POSITIVE-evidence side (recording that a dispatch
# happened), where collapsing `None` to "don't record" is the safe
# `is_registered_review_lens()` (review_agent_registry.py) owns the
# strip-prefix + registry-read + membership check, including the
# "unreadable registry collapses to skip" posture — this is the
# WRITE/POSITIVE-evidence side (recording that a dispatch happened),
# where collapsing an unreadable registry to "don't record" is the safe
# direction: narrowing corroboration can only narrow, never widen, what
# counts as a passing gate later.
registered = read_registered_review_agent_names(default_agents_dir())
if not registered or subagent_type not in registered:
if not is_registered_review_lens(subagent_type):
# Not a real, registered review agent, or the registry could not be
# read at all — never recorded, not even as a rejected/flagged entry
# (module docstring).
return 0

# Normalize the plugin-qualified dispatch form ("dev-team:doc-review") to
# the bare name the registry's closed set uses, so the plugin's normal,
# installed invocation form is recognized identically to a bare-named one.
subagent_type = strip_plugin_prefix(subagent_type)

cwd = payload.get("cwd") or "."
session_id = payload.get("session_id")
tool_name = payload.get("tool_name") or "Agent"
Expand Down
Loading
Loading