Skip to content

feat(seal): opt-in truth-axis --strength-gate for weak claim evidence#18

Open
ajaysurya1221 wants to merge 1 commit into
mainfrom
feature/strength-gate
Open

feat(seal): opt-in truth-axis --strength-gate for weak claim evidence#18
ajaysurya1221 wants to merge 1 commit into
mainfrom
feature/strength-gate

Conversation

@ajaysurya1221

@ajaysurya1221 ajaysurya1221 commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Problem

Load-bearing claims could seal green even when backed by evidence too weak to falsify them — e.g. a
behavior claim backed only by a symbol: existence check, which proves the symbol still exists but
can never prove the behaviour holds. Binding (the trigger axis) already had an opt-in refuse-gate
(--binding-gate), but truth-strength / checker-adequacy was advisory only (strength.py computed
adequacy_mismatch / claim_risk and merely printed them). That left the project's named #1 technical
risk — false confidence from a green-but-weak checker — un-enforced.

Mechanism

Adds the opt-in truth-axis --strength-gate {off,warn,fail} on seal and verify, the companion
to --binding-gate:

  • off (default): preserves prior behaviour exactly (gate branch only runs under fail; diagnostics
    only under warn/fail; strength imported lazily so the default seal path never pulls it in).
  • warn: prints checker-strength / adequacy diagnostics after a successful seal — never blocks.
  • fail: refuses seal/verify (StrengthGateError → exit 4, atomic no-write, before any
    sidecar/store write) when a load-bearing claim is high-risk — a behavior claim backed only by
    existence / raw-text / opaque-shell, a quantity claim backed only by existence, or an unbacked
    claim. Blocking predicate is exactly load_bearing AND risk == "high".

Also fixes a correctness inversion in the underlying adequacy lint: an opaque C5 shell: checker
(strength shell_executable, ranked below existence) was missing from _WEAK_FOR_BEHAVIOR, so a
behaviour claim backed only by a shell silently passed a lint that a stronger existence backing
tripped. shell_executable is now treated as too weak for behavior/quantity claims.

Security impact

Read-only analysis over claim metadata and existing checker specs (strength.analyze /
gate_blocking are pure + read-only ast). No new checker-execution path; policy.executable_kind,
--deny-exec / --deny-shell, trusted-base, and C4/C5 execution policy are unchanged. No warrant
schema change. The refusal maps to the existing seal-refused exit code (4); it never marks a claim
BROKEN/false and never touches trust state or fold/revalidate. This does not make public-fork PRs
safe beyond the repo's existing documented trust boundary.

Tests

The change adds tests/test_adequacy_gate.py (25 tests, TDD red→green) covering the inversion fix, the
gate_blocking matrix (behavior/quantity/fact × existence/raw_text/structural/behavioral/semantic/
shell × load-bearing), the off/warn/fail CLI matrix on seal and verify, atomic no-write,
gate-never-masks-a-false-claim, and the advisory-only fold-path invariant. Existing test_strength.py
stays compatible.

CI (.github/workflows/ci.yml) is the authoritative run — it executes ruff check,
ruff format --check, and the full pytest suite on Python 3.11 / 3.12 / 3.13 (ubuntu, python on
PATH). See the PR checks for results. (Local runs on the author's machine were blocked by host
endpoint-security software stalling Python startup, so CI is the source of truth.)

Invariants verified (from source)

  • default off preserves prior behaviour (CLI + seal_artifact default off; gate only under fail)
  • warn never blocks (no exception; post-seal emission; exit unchanged)
  • fail refuses only load-bearing high-risk truth-strength cases (load_bearing AND risk=="high")
  • gate never marks a claim BROKEN (StrengthGateError(SealError) → exit 4; a false claim is refused
    first at step 2, FAILED_AT_SEAL)
  • fail refusal writes no warrant/sidecar/store entry (gate runs before all writes)
  • no new execution path (policy.py untouched; read-only ast)
  • revalidate / fold unchanged (not in diff; strength not imported there — regression-tested)

Known limitations

  • Gates only the weakest truth-strength mismatches (behavior/quantity kinds); fact/reference/
    decision claims are not kind-flagged (existence is adequate for a fact).
  • A structural (py-signature:) checker clears the gate but does not prove behaviour (the documented
    "gutted body" ceiling); for behavioural proof use a C4 pytest: test.
  • fail is opt-in (default off); field false-alarm behaviour still needs pilot data.
  • This is not an LLM judge — the decision is a pure, inspectable lookup over
    (claim.kind, claim.load_bearing, {checker types}) + a read-only AST lint; no model call at check
    time; the refusal is byte-reproducible and names the exact claim, kind, and strongest checker.

Rollout

Use --strength-gate=warn first (report-only) in CI / the Action config; keep fail opt-in until
production claim sets show acceptable noise and teams are willing to remediate weak evidence. The C4
interpreter contract (python -m pytest via PATH) is intentionally left unchanged.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added --strength-gate option to seal and verify commands with off, warn, and fail modes to control whether weak checkers can verify load-bearing claims. Warn mode reports strength-adequacy issues without blocking; fail mode refuses sealing when checker strength is insufficient.
  • Bug Fixes

    • Fixed strength-adequacy diagnostics to correctly identify weak shell-based checkers.
  • Documentation

    • Added comprehensive documentation and copy-paste demo for the new strength-gate functionality.

Adds --strength-gate {off,warn,fail} on `seal` and `verify` — the truth-axis
companion to --binding-gate. Binding gates WHEN a claim re-checks; strength gates
WHETHER its checker can falsify it. `warn` surfaces checker-strength/adequacy
diagnostics after a successful seal; `fail` refuses (StrengthGateError -> exit 4,
atomic no-write, before any sidecar/store write) when a LOAD-BEARING claim is
high-risk (load_bearing AND risk=="high"): a behavior claim backed only by
existence/raw-text/opaque-shell, a quantity claim backed only by existence, or an
unbacked claim.

Opt-in (default off, byte-identical prior behavior); read-only (pure + read-only
ast, no new execution path; policy.py untouched); never marks a claim BROKEN
(maps to the existing seal-refused exit 4, not a trust/claim state); revalidate
and fold are unchanged (strength stays out of that path, regression-tested).

Also fixes a truth-strength inversion: an opaque C5 shell: checker
(shell_executable, ranked below existence) was missing from _WEAK_FOR_BEHAVIOR,
so the weakest backing silently passed a lint a stronger existence backing
tripped. shell_executable is now treated as too weak for behavior/quantity claims.

Tests: tests/test_adequacy_gate.py (25, TDD red->green). Full suite + ruff run in CI.

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

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

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: 010d4a1c-fdd7-4cc0-af5c-9df0e60f852e

📥 Commits

Reviewing files that changed from the base of the PR and between 6838e62 and 61373e9.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • README.md
  • docs/STRENGTH_GATE_DEMO.md
  • src/dorian/cli.py
  • src/dorian/commands.py
  • src/dorian/seal.py
  • src/dorian/strength.py
  • tests/test_adequacy_gate.py

📝 Walkthrough

Walkthrough

Adds an opt-in --strength-gate off|warn|fail option to dorian seal and dorian verify. In fail mode, sealing is refused (exit 4, no writes) when a load-bearing claim's checker is too weak to falsify its kind. warn emits adequacy diagnostics after a successful seal. strength.py gains shell_executable weak-tier corrections and a gate_blocking helper.

Changes

--strength-gate truth-axis feature

Layer / File(s) Summary
strength.py: tier fixes and gate_blocking helper
src/dorian/strength.py
Adds shell_executable to weak-backing tiers for behavior and quantity claims, updates claim_risk high-risk detection to include shell_executable, fixes quantity mismatch to use strongest-checker condition, and adds gate_blocking(diags) to filter high-risk load-bearing findings.
seal.py: StrengthGateError and strength_gate parameter
src/dorian/seal.py
Adds StrengthGateError(SealError) that encodes blocking claim ids; extends seal_artifact with strength_gate: str = "off"; inserts the post-checkers, pre-write conditional block that lazily imports dorian.strength, runs analysis, and raises StrengthGateError before any sidecar/store write.
CLI and commands wiring
src/dorian/cli.py, src/dorian/commands.py
Adds --strength-gate {off,warn,fail} to both seal and verify subcommands; adds _emit_strength_gate_warnings and _print_strength_gate_refusal helpers; wires strength_gate into seal_artifact; adds except StrengthGateError handlers returning EXIT_REVOKED; emits adequacy diagnostics in warn|fail mode after successful sealing.
Test suite
tests/test_adequacy_gate.py
Adds gate_blocking unit tests, end-to-end off/warn/fail tests for verify and seal (exit codes, warrant presence, stderr content), regression against false-claim masking, warn readback error downgrade, and AST architectural contract asserting fold.py/revalidate.py do not import strength.
Docs: CHANGELOG, README, and demo
CHANGELOG.md, README.md, docs/STRENGTH_GATE_DEMO.md
CHANGELOG records the new feature and shell_executable truth-strength inversion fix; README extends command surface docs with --strength-gate semantics; new demo doc walks through off/warn/fail modes with copy-paste commands and a refusal/allow matrix.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as dorian CLI
  participant seal_artifact
  participant dorian.strength
  participant Store as sidecar/store

  User->>CLI: dorian verify --strength-gate fail
  CLI->>seal_artifact: seal_artifact(..., strength_gate="fail")
  seal_artifact->>seal_artifact: run all claim checkers
  seal_artifact->>dorian.strength: analyze(sealed_claims)
  dorian.strength-->>seal_artifact: diags
  seal_artifact->>dorian.strength: gate_blocking(diags)
  dorian.strength-->>seal_artifact: blocking_findings

  alt blocking_findings non-empty
    seal_artifact-->>CLI: raise StrengthGateError
    CLI->>User: print refusal + exit 4 (no write)
  else blocking_findings empty
    seal_artifact->>Store: write sidecar + update index
    seal_artifact-->>CLI: success
    CLI->>CLI: _emit_strength_gate_warnings (warn|fail mode)
    CLI->>User: exit 0
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ajaysurya1221/dorian#4: Both PRs modify seal_artifact's keyword-only parameter list and control flow in src/dorian/seal.py, so this PR's strength_gate addition sits directly adjacent to the extra_watch changes introduced there.
  • ajaysurya1221/dorian#17: The --binding-gate trigger-only-symbol fix in this PR's CHANGELOG aligns directly with PR #17's bindings.py work expanding _checker_exercised_files via C4 pytest import resolution.

Poem

🐰 A gate for the truth, not just the trigger's trail,
Shell-backed claims now meet a stricter tale.
Warn softly at first, then refuse if you must—
No warrant is written when strength is unjust.
The rabbit hops forward, adequacy in paw,
Sealing with honor, upholding the law! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main feature: an opt-in --strength-gate flag for validating weak claim evidence on the truth-axis.
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 feature/strength-gate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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.

2 participants