Skip to content

reflect: make the mechanical gates detect the shapes this session used - #299

Open
EdbertChan wants to merge 1 commit into
mainfrom
stack/EdbertChan/reflect/hazop-procedure-20260909/make-mechanical-gates-detect-shapes-session-used--e25ea152
Open

reflect: make the mechanical gates detect the shapes this session used#299
EdbertChan wants to merge 1 commit into
mainfrom
stack/EdbertChan/reflect/hazop-procedure-20260909/make-mechanical-gates-detect-shapes-session-used--e25ea152

Conversation

@EdbertChan

@EdbertChanEdbertChan commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Summary

Four mechanical gates were blind to the exact failure shape they exist to catch. This restores each detector's coverage.

The audited session shipped four fixes in one night, each correct, none making the feature work. Every gate stayed quiet.

The ship gate missed six real "it works" claims and treated the PR number of the change as proof the pipeline ran.

The intervention detector read NO on a session with four proof demands, because the user challenged the evidence rather than blaming the agent.

The schema gate armed its pending state on a --dry-run rehearsal, then blocked the real push that followed it.

The learned rule said prove the real path. It did not say how to find the defects, so this adds the enumerate-then-probe procedure.

Review Claim

Each of the four detectors now fires on the real inputs it previously missed, and stays silent on the near-miss inputs beside them.

Review Lane

behavior

Review Unit

engine-runtime

Safety Invariant

Every change is additive to a detector, and every existing test in the repo still passes unchanged: scripts/run_all_tests.sh exits 0 over 32 suites. The two hooks fail open exactly as before -- an unreadable transcript, malformed stdin, or a missing state file still lets the turn through. pr-schema-gate only ever loosens: a --dry-run rehearsal now arms nothing, so the worst case is one un-armed follow-up requirement, never a newly blocked publication. prove-it-ship-gate only ever tightens on claims it already understood, and the widened claim patterns are pinned against four near-miss messages from the same session that must stay silent. token_audit.py adds two frustration kinds; the first-time proof request that must not flag is a test.

Assumptions: proposed unconfirmed -- this PR was drafted from a delegated task specification with no interactive turn available to confirm the invariant text.

Slice Rationale

These four are one review unit and one claim: every mechanical surface that observed this session and reported nothing. Splitting them separates the detector from the evidence that it was blind, and each fix is a handful of lines. The remaining accepted findings (A4, a headless config check; A6, the memory and artifact corrections) are separate units and are not here.

Non-goals

Test Plan

Test Plan

Each item is the same suite run twice: once with only the detector reverted (git stash push <detector>), once whole. Real output pasted.

  • python3 -m unittest discover -s engine/hooks/prove-it-ship-gate/tests (A1)
### A1 engine/hooks/prove-it-ship-gate
-- BEFORE --
ERROR: test_fires_when_the_only_id_is_the_changes_own_pr_number (test_hooks.TestLiveReceiptVsPrReference.test_fires_when_the_only_id_is_the_changes_own_pr_number)
ERROR: test_silent_when_a_live_output_receipt_is_present (test_hooks.TestLiveReceiptVsPrReference.test_silent_when_a_live_output_receipt_is_present)
FAIL: test_fires_on_each_claim_shape_the_session_used (test_hooks.TestSessionClaimShapes.test_fires_on_each_claim_shape_the_session_used)
FAILED (failures=6, errors=6)
Ran 14 tests in 0.004s
-- AFTER --
OK
Ran 14 tests in 0.003s
  • python3 -m unittest discover -s engine/skills/reflect/scripts/tests -p test_token_audit.py (A2)
### A2 engine/skills/reflect/scripts/token_audit.py
-- BEFORE --
FAIL: test_detects_each_real_proof_challenge_turn (test_token_audit.TestProofChallengeAndRestatedAsk.test_detects_each_real_proof_challenge_turn)
FAIL: test_four_proof_challenges_flag_intervention_must_automate (test_token_audit.TestProofChallengeAndRestatedAsk.test_four_proof_challenges_flag_intervention_must_automate)
FAILED (failures=5)
Ran 72 tests in 0.050s
-- AFTER --
OK
Ran 72 tests in 0.051s
  • python3 -m unittest discover -s engine/hooks/pr-schema-gate/tests (A3)
### A3 engine/hooks/pr-schema-gate
-- BEFORE --
FAIL: test_dry_run_arms_nothing_and_never_blocks_the_real_push (test_hooks.TestStackFollowUpHook.test_dry_run_arms_nothing_and_never_blocks_the_real_push)
FAIL: test_dry_run_push_is_not_a_publication (test_hooks.TestStackFollowUpDetect.test_dry_run_push_is_not_a_publication)
FAILED (failures=4)
Ran 57 tests in 0.034s
-- AFTER --
OK
Ran 57 tests in 0.034s
  • python3 -m unittest discover -s tests -p test_hazop_procedure.py (A5)
### A5 corpus/CLAUDE.learned.md
-- BEFORE --
FAIL: test_defect_count_is_published_before_the_first_fix_commit (test_hazop_procedure.TestHazopProcedure.test_defect_count_is_published_before_the_first_fix_commit)
FAIL: test_eight_numbered_steps_each_carry_their_method_attribution (test_hazop_procedure.TestHazopProcedure.test_eight_numbered_steps_each_carry_their_method_attribution)
FAIL: test_enumeration_is_separated_from_fixing (test_hazop_procedure.TestHazopProcedure.test_enumeration_is_separated_from_fixing)
FAIL: test_every_cited_method_resolves_to_a_fetched_source_url (test_hazop_procedure.TestHazopProcedure.test_every_cited_method_resolves_to_a_fetched_source_url)
FAIL: test_guide_word_matrix_lists_every_iec_61882_guide_word (test_hazop_procedure.TestHazopProcedure.test_guide_word_matrix_lists_every_iec_61882_guide_word)
FAIL: test_leveson_whack_a_mole_passage_is_quoted_verbatim (test_hazop_procedure.TestHazopProcedure.test_leveson_whack_a_mole_passage_is_quoted_verbatim)
FAILED (failures=28)
Ran 6 tests in 0.005s
-- AFTER --
OK
Ran 6 tests in 0.001s
  • bash scripts/run_all_tests.sh -- whole repo, exit=0, 32 suites, zero FAILED lines.

  • python3 engine/skills/make-pr/scripts/preflight.py --base origin/main

unit engine-runtime: 6 file(s)
neutral 2 file(s): corpus/CLAUDE.learned.md, tests/test_hazop_procedure.py
declare Review Unit: engine-runtime
gate python3 scripts/check_hook_test_coverage.py engine/hooks/pr-schema-gate
check_hook_test_coverage: OK (1 hook(s) checked)
gate python3 scripts/check_hook_test_coverage.py engine/hooks/prove-it-ship-gate
check_hook_test_coverage: OK (1 hook(s) checked)
gate python3 scripts/check_skills_three_harnesses.py
ok skills three-harness check
gate python3 scripts/check_ecosystem_boundaries.py
ok ecosystem boundaries
gate python3 scripts/check_skill_file_refs.py
ok skill file refs
gate python3 scripts/check_skill_test_coverage.py
ok skill test coverage
gate python3 scripts/check_skill_trigger_mechanism.py
ok skill trigger mechanism
ok preflight passed
  • python3 scripts/check_no_new_comments.py --base origin/main -> ok no new comments
  • python3 scripts/check_no_dated_provenance.py --base origin/main -> ok no dated provenance
  • python3 scripts/check_codify_has_code.py --base origin/main -> ok codify-has-code

Diff atomicity: one warning, unrelated-areas (corpus, engine, tests). Confirmed intentional -- the detector, its tests, and the rule prose are one claim.

Two classifier notes, disclosed rather than worked around:

  • node engine/skills/draft-pr/scripts/validate-pr-body.mjs rejects this body with Review lane behavior cannot ship with docs files in the same PR. It reaches that by classifying corpus/CLAUDE.learned.md under docs-by-extension (**/*.{md,mdx}) in drafter.config.json. The make-pr overlay's own preflight classifies the same file as neutral (preflight.py's review_unit_for returns None for it). Two classifiers over the same input disagree, which is the sibling-classifier-drift shape. Nothing here was relabelled and no rule was loosened to pass -- reporting the disagreement instead. validate-pr-body.mjs is not a CI gate in this repo (.github/workflows/ci.yml installs the toolchain but never invokes it), so this is advisory.
  • The four items ship together because they are one claim; splitting the always-loaded rule out to satisfy the docs rule would put the diagnosis prose in a PR with no detector beside it, which is what check_codify_has_code.py exists to prevent.

Revert Plan

Revert Plan
  • Safe to revert? Yes
  • Revert command: git revert <sha>
  • Post-revert steps: none. The hooks read their state from $TMPDIR, not the repo, so no stale state survives a revert. Reverting restores the previous detectors exactly.
  • Data migration? No

Note

Medium Risk
Changes when Stop/PreToolUse hooks block agent output and shell commands; mis-tuned regex could false-positive ship claims or false-negative proof challenges, but scope is detection logic plus tests, not production data paths.

Overview
Tightens reflect-derived mechanical gates so they catch phrasing and workflows that slipped through in a session that shipped multiple unproven fixes.

prove-it-ship-gate now treats claims like “Proof: yes”, “proven”, “confirmed working”, and “all … are done” as live ship assertions, expands live-context nouns (nightly, pipeline, merge queue, etc.), and stops counting bare #12345 PR refs as evidence. Live-output receipts (workflow ids, Actions run URLs, daily-* tags, live-owner dispatch) satisfy the gate; citing only the PR under review does not.

pr-schema-gate no longer treats mergify stack push --dry-run as a publication that arms the create-pr follow-up lock, so a rehearsal cannot block the real push.

token_audit adds restated-ask and proof-challenge frustration patterns and folds them into intervention-must-automate, matching polite repeated “prove it” demands instead of only blunt “you messed up” signals.

CLAUDE.learned.md replaces vague “prove the real path” guidance with an eight-step, attributed enumerate-then-probe procedure (HAZOP / SRE); tests/test_hazop_procedure.py pins step order, citations, and guide words in that doc.

Reviewed by Cursor Bugbot for commit 3481f0e. Bugbot is set up for automated code reviews on this repo. Configure here.

Four accepted reflect findings from one 10-hour session that shipped four
unproven fixes. Each gate that should have caught it was blind to the exact
shape in front of it.
prove-it-ship-gate (A1): CLAIM_RE had no pattern for "Proof: yes", "proven",
"confirmed working", or "all three asks are done", so six real ship claims
read as silence. has_evidence() also accepted any `#\d{3,6}`, which means the
PR number of the change under review counted as proof that the pipeline ran.
A live-output receipt (workflow id, Actions run, release tag, live-owner
dispatch) is now a distinct predicate from a bare PR reference.
token_audit.py (A2): intervention-must-automate read NO on a session with
four same-class proof demands. told-you needs "i told you"; this user
challenges the evidence instead of blaming the agent, in a politer register
with no pattern. Adds restated-ask and proof-challenge.
pr-schema-gate (A3): `mergify stack push --dry-run` armed the pending
follow-up state, so the real push that followed was blocked. Cost five of the
session's fifteen tool errors, with the workaround already in memory. A
rehearsal must not have the side effects of the real operation.
CLAUDE.learned.md (A5): replaces the interim "prove the real path" prose with
the enumerate-then-probe procedure it was missing -- eight steps from
IEC 61882 HAZOP and Google SRE ch. 12, each attributed, each with a gate.
Repro-then-fix and one-variable isolation both terminate on the first cause;
neither asks whether a second stage also failed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HVGJAQuwdDArq4oGK2wrSE
Change-Id: Ie25ea152fdc94b3896cc93768c71b49afb77b617
@cursor

cursorBot commented Sep 9, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_29ff57c0-0b3a-4cd7-b0b1-1868050530ad)

Sign up for freeto 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.

1 participant

@EdbertChan