Skip to content

fix(sdlc): resolve reform-complete predicate through the gate shim + test gatherer boundary + repoint timer#3842

Merged
ryanklee merged 1 commit into
mainfrom
delta/reform-complete-predicate-fix-20260601
Jun 1, 2026
Merged

fix(sdlc): resolve reform-complete predicate through the gate shim + test gatherer boundary + repoint timer#3842
ryanklee merged 1 commit into
mainfrom
delta/reform-complete-predicate-fix-20260601

Conversation

@ryanklee
Copy link
Copy Markdown
Collaborator

@ryanklee ryanklee commented Jun 1, 2026

Reform fix — reform-complete predicate false-negatives + uninstalled regression timer

The #3833 mechanical "is the coordination reform realized?" predicate was itself doubly broken — the THIRD merged-vs-realized drift, in the tool meant to detect them.

Root cause (reproduced live before fixing)

scripts/hapax-reform-complete grepped cc-task-gate.sh for is_cognition_path, escape_grant_allows, _record_retro_grant_obligation, DEPRECATED. But #3832 collapsed that file into a thin HAPAX-GATE-SHIM and moved every marker into cc-task-gate.impl.sh (deployed canonical at $HAPAX_CANONICAL_HOOKS). So canonical-gate (INV-5), escape-grant, off-deprecation reported permanent FALSE-NEGATIVE FAILs — they could never enter passed_ever, blinding --regression-only exactly when a silent revert matters.

Live before:

FAIL canonical-gate  — INV-5 (is_cognition_path) missing from live gate; INV-5 missing from repo gate
FAIL escape-grant    — gate does not call escape_grant_allows
FAIL off-deprecation — gate lacks retro-grant obligation recording; HAPAX_*_OFF not marked DEPRECATED

Live after:

PASS canonical-gate / escape-grant / off-deprecation   (resolved through impl/canonical)
FAIL coord-verbs                                        (honest red — all 49 verbs are dry-run stubs)

Changes

  • _resolve_gate_text() — resolves a HAPAX-GATE-SHIM to its real impl, mirroring the shim's own order (deployed canonical first, then co-located cc-task-gate.impl.sh), skipping a candidate that is itself a shim. Wired into _has_inv5 / gather_escape_grant / gather_off_deprecation. Returns the shim text verbatim when no impl resolves, so a truly-missing impl stays an honest failure.
  • shadow-cutover deliberately NOT resolved — the only policy_decide token in the impl is a non-enforcing comment (a shadow-replay pointer); resolving would false-positive the genuinely-incomplete 3b cutover. It stays honest, passing on predicate_reachable. (Inline comment documents this so a future "consistency fix" doesn't reintroduce the false positive.)
  • TestShimResolution (8 tests) — drives the gatherers against a materialized shim+impl pair (the boundary the decider-only tests never exercised); fails if a gatherer reads only the shim. A reverted-resolver simulation confirms the 3 gatherer tests fail (genuine regression guard, not vacuous).
  • hapax-reform-complete.service — ExecStart repointed off the stale primary worktree (%h/projects/hapax-council, which floats on feature branches) onto the deploy worktree (%h/.cache/hapax/rebuild/worktree) + ConditionPathExists to convert a 203/EXEC crashloop into a clean skip. Same hardcoded-primary-worktree hazard fixed for hapax-sdlc-invariants.service in fix(sdlc): activate inert INV-1..5 trace-checker + unify auto-mint onto the live escape-grant contract #3839.

Acceptance criteria

Verification

  • pytest tests/test_reform_complete.py50 passed
  • ruff check + pyright → clean
  • Live hapax-reform-complete run → 3 false-negatives now PASS, no new false positives
  • Independent code review (resolver termination/safety, shadow-cutover non-resolution, regression-guard validity, 5 edge cases, false-positive vectors) → no high-confidence issues

Task: reform-complete-predicate-fix-20260601 · AuthorityCase: CASE-SDLC-REFORM-001

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Resolved false negatives in gate file detection for shimmed implementations
    • Prevented service crash-loops by validating required deployment directory exists before startup
  • Improvements

    • Updated service to reference active deployed worktree path instead of hardcoded directory location
  • Tests

    • Added comprehensive test coverage for shimmed gate file resolution scenarios

…test the gatherer boundary + repoint the timer

The #3833 reform-complete predicate grepped cc-task-gate.sh for is_cognition_path /
escape_grant_allows / _record_retro_grant_obligation / DEPRECATED, but #3832 moved
those into cc-task-gate.impl.sh and left cc-task-gate.sh a thin HAPAX-GATE-SHIM. So
canonical-gate (INV-5), escape-grant and off-deprecation reported permanent
FALSE-NEGATIVE FAILs — they could never enter passed_ever, blinding --regression-only
exactly when a silent revert matters (the 3rd merged-vs-realized cycle, in the tool
meant to detect them).

- Add _resolve_gate_text(): if a gate is a HAPAX-GATE-SHIM, resolve to the real impl
  mirroring the shim's own order (deployed canonical $HAPAX_CANONICAL_HOOKS first, then
  co-located cc-task-gate.impl.sh), skipping a candidate that is itself a shim. Wire it
  into _has_inv5 / gather_escape_grant / gather_off_deprecation. shadow-cutover keeps
  reading the RAW gate deliberately: the only policy_decide token in the impl is a
  non-enforcing comment, so resolving would false-positive the genuinely-incomplete 3b
  cutover. The raw-shim sha (live_matches_repo) is unchanged — it operates on the shim
  layer, complementary to INV-5 presence on the resolved impl.
- Add TestShimResolution: drives the gatherers against a materialized shim+impl pair
  (the boundary the decider-only tests never exercised); fails if a gatherer reads only
  the shim. Honest-negative cases (no resolvable impl -> False) asserted too.
- Repoint hapax-reform-complete.service ExecStart off the stale primary worktree onto
  the deploy worktree (%h/.cache/hapax/rebuild/worktree) + ConditionPathExists, fixing
  the same hardcoded-primary-worktree hazard as #3839. The 6h timer auto-enables on
  merge via its existing Hapax-Auto-Enable marker; --verify-auto-enable already detects
  + loudly fails a missing install.

Live: canonical-gate, escape-grant, off-deprecation now PASS (resolving through
impl/canonical); only coord-verbs remains an honest red. 50 tests, ruff, pyright green.
Timer install/enable + scheduled-run watermark population are realized via the deploy
chain (reform-deploy-chain-repair, #3840) on merge, mirroring #3839's deferral.

Task: reform-complete-predicate-fix-20260601
AuthorityCase: CASE-SDLC-REFORM-001

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 731c08e7-b5f6-47c3-a40b-c5573fda9f21

📥 Commits

Reviewing files that changed from the base of the PR and between d46c933 and fdd1704.

📒 Files selected for processing (3)
  • scripts/hapax-reform-complete
  • systemd/units/hapax-reform-complete.service
  • tests/test_reform_complete.py

📝 Walkthrough

Walkthrough

The PR introduces shim-aware gate-file resolution to avoid false negatives when checking for deployment markers in shimmed cc-task-gate.sh files. The script now reads deployed canonical implementations or colocated impl files, gatherer functions use the resolved text for predicate detection, the systemd service switches to deploy-worktree execution paths with safeguards, and new tests validate the shim resolution pathway.

Changes

Shim-aware gate resolution and service integration

Layer / File(s) Summary
Shim resolution infrastructure
scripts/hapax-reform-complete
Introduces SHIM_MARKER constant, _resolve_gate_text() helper to locate and read canonical or colocated implementation files, and updates _has_inv5() to detect is_cognition_path markers through resolved gate text.
Gatherer function updates
scripts/hapax-reform-complete
gather_escape_grant determines gate_wired via resolved text, gather_shadow_cutover adds clarifying comment that it intentionally reads raw text, and gather_off_deprecation sources obligation markers from resolved gate text.
Service worktree configuration
systemd/units/hapax-reform-complete.service
Adds ConditionPathExists guard to prevent crashloops when worktree is unprovisiond, and changes ExecStart to run from active deploy rebuild worktree under %h/.cache/hapax/rebuild/worktree instead of hardcoded primary session path.
Shim resolution test suite
tests/test_reform_complete.py
Materializes shimmed cc-task-gate.sh and optional cc-task-gate.impl.sh files, validates shim-resolved gate text reading, INV-5 marker detection through shims, gate_wired detection when impl is available, and off-deprecation marker discovery in resolved implementations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • hapax-systems/hapax-council#3833: Both PRs modify scripts/hapax-reform-complete INV-5 and escape-grant/off-deprecation detection logic, with this PR adding the shim-resolution layer to detect markers in deployed implementations.
  • hapax-systems/hapax-council#3741: This PR's shim-resolution infrastructure enables detection of is_cognition_path and other markers added to hooks/scripts/cc-task-gate.sh in that PR.

Poem

🐰 A shim that hid the truth so deep,
Now resolves to where real gates sleep,
Markers found where they belong at last,
While worktree paths shed hardcoded past!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is comprehensive and well-structured, covering root cause, changes, and acceptance criteria. However, the required AuthorityCase template fields (Case and Slice) are missing from the description itself. Add the AuthorityCase fields to the description: Case: CASE-SDLC-REFORM-001, Slice: (specify the appropriate slice number). Also add a Test plan section if not already documented elsewhere.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main changes: resolving reform-complete predicates through the gate shim, testing the gatherer boundary, and repointing the timer.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch delta/reform-complete-predicate-fix-20260601

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fdd1704bb4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +273 to +275
for candidate in (
_canonical_hooks_dir() / "cc-task-gate.sh",
path.parent / "cc-task-gate.impl.sh",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Read repo shims from their colocated impl

When this helper is used for repo_gate (and lane gates), preferring $HAPAX_CANONICAL_HOOKS/cc-task-gate.sh masks regressions in the checkout under test: if the deployed canonical gate still contains is_cognition_path but the current repo's hooks/scripts/cc-task-gate.impl.sh has been reverted or is missing, _has_inv5(repo_gate) still returns true. I checked hooks/scripts/hooks-doctor.sh and the deploy path installs the repo impl as the canonical gate, so the predicate needs to verify the colocated repo impl for repo-source checks rather than the already-deployed copy, otherwise canonical-gate can pass while the source that will be deployed is broken.

Useful? React with 👍 / 👎.

Comment on lines +281 to +282
if SHIM_MARKER not in ctext:
return ctext
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Follow canonical shims before falling back locally

When $HAPAX_CANONICAL_HOOKS points at a different shim directory, this skips that canonical shim and falls back to the original checkout's colocated impl, but the real hooks/scripts/cc-task-gate.sh only skips the canonical path when it is the same inode and otherwise execs it. In the misconfigured or partially deployed case where the canonical shim has no colocated impl, the live hook fails open, while this resolver reads the caller's local impl and reports INV-5/escape/off-deprecation as wired, so the regression detector can pass exactly the bad canonical-shim state it is meant to catch.

Useful? React with 👍 / 👎.

# absent) code — the same hardcoded-primary-worktree hazard fixed for
# hapax-sdlc-invariants.service in #3839. The rebuild worktree tracks deployed main and
# is rebuilt idempotently by hapax-post-merge-deploy.
ExecStart=/home/hapax/.local/bin/uv run --directory %h/.cache/hapax/rebuild/worktree python scripts/hapax-reform-complete --regression-only
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep live/source comparison off the deploy cwd

With the timer now running the script from %h/.cache/hapax/rebuild/worktree, REPO_ROOT inside hapax-reform-complete is the same deploy worktree that the LIVE_GATE constant points to, so gather_canonical_gate() hashes the same hooks/scripts/cc-task-gate.sh file for both live_sha and repo_sha. In the scheduled regression-detector context, a rebuild-worktree gate drift therefore makes live_matches_repo stay true instead of reporting the divergence the canonical-gate check is documented to catch.

Useful? React with 👍 / 👎.

@ryanklee ryanklee added this pull request to the merge queue Jun 1, 2026
Merged via the queue into main with commit 422bd46 Jun 1, 2026
35 checks passed
@ryanklee ryanklee deleted the delta/reform-complete-predicate-fix-20260601 branch June 1, 2026 17:58
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.

1 participant