| name | harness-e2e-check |
| description | On-demand end-to-end integration check of the dev-team plugin's own harness mechanisms — failure-class routing, dead-end detection, evidence bundles, invariants/rollback, the REFACTOR-phase test-freeze guard family, lesson-validation weighting, and the handoff rename — running each live rather than trusting a per-PR test result. Originated as issue #907's post-merge integration test plan; this is that plan made repeatable. Use when the user says "run the harness e2e check", "re-run 907", "smoke-test the harness", or after any batch of harness-mechanism changes lands on main. |
| argument-hint | [--item N] [--output <path>] |
| user-invocable | true |
| allowed-tools | Read, Glob, Grep, Bash(python3 *, git *, pytest *), Write |
Harness E2E Check
Role: worker. This command drives real, live exercises of the harness's own
mechanisms in throwaway scratch fixtures and reports pass/fail with evidence
— it does not modify the plugin, and it is not a substitute for /agent-eval
(per-agent detection accuracy) or /harness-audit (usage-metrics-driven
staleness analysis). It exists because those mechanisms only prove
themselves working together, in a live run, not from each one's own
isolated unit tests.
Worker constraints
- Read-only against the plugin itself. All exercises run inside scratch
directories (a fresh
mktemp -d per item, or the caller's --output
sibling) — never inside the plugin's own working tree.
- Live, not simulated. Where a mechanism can be exercised without an
LLM call (guard hooks,
lesson_validate.py, structural gates,
stale-reference scans), run the real script/hook against a real fixture —
never hand-wave "this should work." Where a mechanism genuinely requires
a live /build run (Steps 3-4 below), drive it for real via /headless-run
or an equivalent live session — do not substitute a description of what a
run would show.
- Be concise. Report each item as one line (pass/fail + one-line
evidence pointer), then a short summary. Full transcripts/output go to
the scratch dir, not chat.
- Every run maintains
references/watchlist.md. See "Hardening over
time" below — this is not optional bookkeeping, it's the point of running
this repeatedly instead of once.
Parse Arguments
Arguments: $ARGUMENTS
- No argument: run all 8 items below.
--item N: run only item N (1-6).
--output <path>: write the full report to a specific path. Default:
.dev-team-reports/harness-e2e-check-<date>.md.
The 8 items
Each item mirrors one from issue #907's original test plan. Item numbers are
stable — do not renumber even if an item is skipped or split.
Item 1 — Full automated suite
Run the repo's actual CI-equivalent gate (scripts/ci-local.sh, or the
component pytest suites directly: plugins/dev-team/tests, tests/repo,
tests/agents, tests/commands, tests/scripts, tests/hooks). Zero
regressions is the bar — a red suite is a fail for this item, full stop.
Item 2 — Structural gates
Run scripts/check_md_references.py, the knowledge/index.json freshness
check, and the citation-lint suite. All clean.
Item 3 — /build end-to-end smoke test
python3 "${CLAUDE_PLUGIN_ROOT}/skills/harness-e2e-check/scripts/make_toy_repo.py" \
--target <scratch>/toy-repo --date "$(date +%F)"
Then drive a real /build run against <scratch>/toy-repo/plans/calc-ops.md
(via /headless-run or an equivalent live session with
${CLAUDE_PLUGIN_ROOT} resolved to this plugin's own checkout). Confirm, from
real output, not description:
- Failure-class routing fires on the deliberate Slice 1 bug (
behavioral-test
class, inline-fix route).
- Dead-end detection does not fire (the iteration-1 → iteration-2 failure
signature changes).
- The 4-section evidence bundle renders with real data.
- Slice 2's
Invariants/Rollback point/Files are honored.
- Gate-decision audit entries carry
proposed/evidence_shown/risks_surfaced.
This fixture is also the regression bait for the three open SKILL.md-drift
gaps in references/watchlist.md (#915, #916, #917) — check those too while
you're in here, per the watchlist's "how to re-check" column.
Item 4 — Refactor-freeze smoke test
In the same toy repo, during a REFACTOR-phase step: attempt a Write/Edit
test-file change (must block via refactor_test_freeze_guard.py), a
recognized Bash shape like sed -i against a test file (must block via
refactor_test_bash_guard.py, #906), and a genuinely unrecognized Bash shape
(must fall through to the revert-guard safety net and emit
decision: "revert" to .claude/metrics/boundary-events.jsonl). This is also where
#913 (no Python detection in is_test_file()) and #914 (compound-command
first-match-wins gap) live — #914 already has a standing regression test
(tests/hooks/test_refactor_test_bash_guard.py, xfail(strict=True)); no
need to hand-re-verify it here, just note whether it's still xfail or has
flipped (which would mean someone fixed it without updating the watchlist).
Item 5 — feedback-learning + harness-audit combined run
python3 "${CLAUDE_PLUGIN_ROOT}/skills/harness-e2e-check/scripts/make_lesson_fixtures.py" \
--target <scratch>/lesson-fixture --mode validated
python3 "${CLAUDE_PLUGIN_ROOT}/skills/harness-audit/scripts/lesson_validate.py" \
--changelog <scratch>/lesson-fixture/metrics/config-changelog.jsonl \
--digest <scratch>/lesson-fixture/metrics/session-digest.jsonl \
--apply -o <scratch>/lesson-fixture/memory/lesson-validation.json
Confirm verdict "validated", and that the changelog append stayed
byte-identical-prefix (append-only). Repeat with --mode harmful and confirm
a rollback proposal (requires_human_approval: true, never an automatic
rollback). Repeat with --mode insufficient and confirm "insufficient data" — never "neutral" on a thin sample.
Item 6 — /handoff rename verification
Covered permanently by
tests/repo/test_no_stale_context_summarization_references.py — this item
is "confirm that test is still green," not a fresh manual grep.
Output format
One line per item (✅ item N — <one-line evidence> or ❌ item N — <what failed>), then update references/watchlist.md per its own
instructions, then a short summary. Full command transcripts go to the
scratch dir or --output path, not chat.
Hardening over time
This skill is meant to get stricter every time it finds something, not stay
a fixed 8-item checklist forever:
- Every newly-found gap gets a watchlist row and a follow-up issue — see
references/watchlist.md's own instructions. Do not fix a finding inline
here; this command reports, /apply-fixes or a normal implementation
pass changes the plugin.
- Prefer promoting a live-run check to a hard pytest regression the moment
it's mechanically possible — item 5's
lesson_validate.py fixtures and
item 4's #914 xfail(strict=True) test are the pattern: encode the
desired behavior as a real assertion now, marked expected-to-fail (or
scripted-but-manually-triggered) while the gap is open, so a fix is caught
automatically instead of relying on someone remembering to re-check by
hand.
- When a fixture accidentally reproduces a gap (like
make_toy_repo.py
baiting #915/#916/#917 just from its natural shape), keep the fixture as
it is and document the coincidence in the watchlist rather than
"fixing" the fixture to stop tripping it — a fixture that stops
reproducing a real gap is worse than one that never did.