Skip to content

feat(assail): route languages through a tested table; retire the vacuous PA1 - #288

Merged
hyperpolymath merged 14 commits into
mainfrom
claude/pa1-routing-table
Nov 10, 2026
Merged

hyperpolymath merged 14 commits into
mainfrom
claude/pa1-routing-table

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

This replaces #282, which GitHub would not retarget from the closed #279's branch ("part of a stack"). The branch and its changes are the same, now merged with current main.

What

The Idris2 PatternCompleteness.idr (PA1) is replaced by the code that actually does the routing, plus exhaustive tests.

  • New src/assail/routing.rs:
    • route(Language) -> Route is an exhaustive match with no wildcard.
    • Route::analyzer() names the analyzer each route reaches.
    • runs_cross_language(is_configuration) returns !is_configuration.
  • analyzer.rs: the dispatch in analyze_inner now matches on route(file_lang). So the table is the code that runs, not a model of it. Only the match arm heads changed, plus the cross-language guard.
  • src/types.rs: adds Language::ALL (52 variants). An exhaustive ordinal test keeps it complete.

Claims and how they are tested (status TESTED)

Each test was seen to fail on a planted fault.

Claim Test Planted fault it caught
(a) Every language analyzer is reached every_language_analyzer_is_reached an unrouted analyze_chapel
(b) No language falls back to the generic analyzer while a dedicated one exists no_language_falls_back_while_a_dedicated_analyzer_exists Java sent to Generic
(c) Cross-language checks run exactly on non-configuration content cross_language_checks_run_exactly_off_configuration (a Justfile plus main.lua, end to end) runs_cross_language forced to true
(d) The README's language counts match the table readme_language_counts_match_the_table the README's stale 49

Routing is not coverage. Language::Unknown goes to InputAdapter, and a file there with no adapter is marked unsupported and skipped. PROOF-NEEDS.adoc says so.

Retired

  • src/abi/PatternCompleteness.idr, for three reasons:
    • It was vacuous: GenericAnalyzer inhabited its witness for every language.
    • It was stale: it covered 50 of 52 languages.
    • It was partly false: it said cross-language checks always run.
  • PROOF-PROGRAMME, PROOF-NEEDS and EXPLAINME now point PA1 at src/assail/routing.rs.
  • The pa1 entry in 0-AI-MANIFEST.a2ml is deleted (a deletion only).
  • The README now says 51 supported languages instead of 49, in the badge, the capabilities list and the summary.

Found, not fixed here (recorded as open obligations in PROOF-NEEDS)

  • Unquoted http:// URLs are missed by the cross-language check. analyze_cross_language strips // comments from every file, which also cuts curl http://host in shell and Justfile recipes.
  • PA1 (a) to (c) still need a proof with Creusot/Pearlite and Verus.

Not changed

.machine_readable/6a2/{META,NEUROSYM,STATE}.a2ml still name PatternCompleteness.idr. They are legacy A2ML files, so they are left for the owner or the deed conversion.

Verification

  • cargo test --lib: 482 passed, 0 failed, after merging current main.
  • cargo fmt --check passes.
  • Against main, the diff is only this PR's 10 files.

Generated by Claude Code

claude added 14 commits November 9, 2026 14:01
Checked with Idris2 0.7.0 (the version proven-tests.yml pins). On main,
two of the five src/abi modules did not compile:

- Stripping.idr: a dangling `|||` doc block at the end of the file was
  a parse error. Behind it, `stripLineCommentsIdempotent` had two real
  type errors: a `case c of '/' => Refl` branch the comment called
  impossible was not refuted, and `decEq` was used without importing
  it. Matching on a Char literal only reduces when the character is a
  literal, so the proof stuck on a variable head.

  The model now classifies each character once (`cls`: Slash, Newline,
  Other) and steps on the class; each proof carries the class with the
  equation `cls c = k`, so every case reduces. The theorem statements
  and all seven sanity checks are unchanged and pass. The new model
  computes the same function as the old pattern-matching one: checked
  exhaustively on all 349,525 strings of length <= 9 over `/`, newline,
  `x` and space, with no mismatch.

- Types.idr: a named field in a one-line data declaration, and an Ord
  instance with no Eq instance. Both fixed without changing meaning.
  Its header claimed three proofs the file does not contain; it now
  says it declares types only, and notes its drift from src/types.rs.

Negative controls: a planted false lemma and a planted non-terminating
definition are both rejected, so the check can fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jma5ixtpeZyJRmfoSsC98u
PROOF-NEEDS.adoc now uses the proof policy's §5 status tokens and §1.2
verifier mapping, pinned to standards 9bdf864, in place of check marks.
Each status rests on a recorded receipt: Idris2 0.7.0 run over src/abi
at 3dc4728, with the invocation, pass criterion and negative controls.

What the re-check found, and how it is now recorded:

- Stripping: did not compile on main; repaired in 3dc4728. PROVEN for
  the model; model-to-Rust correspondence ASSUMED.
- Attestation: PROVEN relative to its hypotheses. Two of them, an
  injective chain hash and perfect unforgeability, are symbolic-model
  idealisations stronger than collision resistance and EUF-CMA, so no
  computational result is claimed.
- PA1 (pattern completeness): compiles but is vacuous, because a
  generic analyzer witness inhabits every language. rustc's
  exhaustiveness check on the `_ => analyze_generic` match already
  gives the guarantee. The model is also stale (50 of 52 languages;
  cross-language checks are now skipped for configuration files).
- Implementation obligations on Rust behaviour (stripping, Patch Bridge
  reachability, taint analysis) are OPEN for Creusot/Pearlite and
  Verus. The missing CI gate for src/abi is OPEN.
- The Kani note is backed by compiling every non-example target with
  unsafe_code forbidden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jma5ixtpeZyJRmfoSsC98u
The Idris2 modules are named PanicAttack.ABI.<M> but lived in src/abi/,
so `idris2 --check src/abi/<M>.idr` failed on a module-name mismatch
from any directory. No CI job checked them, which is how Stripping.idr
sat on main not compiling while PROOF-NEEDS called it closed.

- Move src/abi/*.idr to src/abi/PanicAttack/ABI/ (pure renames) and
  add src/abi/panic-attack-abi.ipkg listing the five modules.
- Add the `abi-proofs` job to proven-tests.yml: every PR and push to
  main runs `idris2 --typecheck src/abi/panic-attack-abi.ipkg` and
  fails on a non-zero exit or any `Error:` line. It reuses the
  framework job's pinned installer and Idris2 cache key, and only the
  actions that workflow already locks, so actions.lock is unchanged.
- PROOF-NEEDS.adoc: the gate is now the receipt; the first local
  receipt is kept; the gate row leaves the open list. EXPLAINME and
  PROOF-PROGRAMME point at the new paths. CHANGELOG history and the
  retired .a2ml files are left as they are.

Checked locally: the package type-checks (Idris2 0.7.0); a planted
false lemma and a planted missing import both fail it; the job's run
step passes as written; actionlint 1.7.7 is clean; validate-sha-pins
and check-allowed-actions pass with the checksum-pinned yq v4.54.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jma5ixtpeZyJRmfoSsC98u
…ous PA1

PA1 was an Idris2 model of the analyzer dispatch whose theorem could not
fail: `GenericAnalyzer : HasAnalyzer lang` inhabited its witness for every
language. It was also stale (50 of 52 languages) and partly false (it said
cross-language checks always run; they are skipped for configuration).

The routing is now real code with claims that can fail:

- src/assail/routing.rs: `route(Language) -> Route`,
  `Route::analyzer()`, and `runs_cross_language(is_configuration)`.
  `analyze_inner` matches on `route(file_lang)` and calls
  `runs_cross_language`. Only the arm heads changed; every arm body is
  byte-identical. `route` and the dispatch are exhaustive with no
  wildcard (Chapel, the one language without a dedicated analyzer, is
  routed to Generic explicitly).
- src/types.rs: `Language::ALL` (52 variants), kept complete by an
  exhaustive `ordinal` match test, following WeakPointCategory::ALL.
- Tests, exhaustive over Language::ALL:
  (a) every language analyzer in analyzer.rs is reached;
  (b) no language falls back to analyze_generic while a dedicated
      analyzer for it exists;
  (c) cross-language checks run exactly off configuration, and on
      scripts embedded in it (Justfile + Lua scan, end to end);
  (d) README's language counts equal the supported count.
  Each was seen to fail on a planted fault.
- README: 49 -> 51 languages (badge, capabilities, summary); (d) caught
  the drift. C and Php were added after the count was written.
- PatternCompleteness.idr removed from src/abi and the ipkg; PROOF-NEEDS,
  EXPLAINME, PROOF-PROGRAMME and the 0-AI-MANIFEST entry updated. PA1's
  status is TESTED; the Creusot/Pearlite and Verus proof is OPEN.

Found while testing (c), recorded as an open obligation, not fixed here:
the cross-language check strips `//` comments before matching, which
also cuts unquoted `http://` URLs (shell, Justfile recipes).

Checked: cargo fmt; clippy -D warnings with all and default features;
cargo test --all-features (789 passed, 0 failed); the Idris2 package
type-checks (4 modules); panic-attack's self-scan reports nothing new.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jma5ixtpeZyJRmfoSsC98u
Addresses the CodeRabbit review of this PR. Each Rust claim was run
against strip_proof_comments copied verbatim from main:

- `//x`: the model gives three spaces, Rust gives "". The model-to-Rust
  row now records a mismatch instead of ASSUMED, and the Stripping.idr
  header and section comment say the model does not reproduce the Rust
  output. The 349,525-input check is labelled model against model.
- `a//*x*/*b*/c` -> `a/*b*/c` -> `ac`: Rust is not idempotent.
- `a/*x*/b` -> `ab`: Rust does not preserve positions.
- Found while checking: blocks are stripped before line comments, so a
  block opener inside a line comment hides the code after it. The
  Lean, Agda/Haskell and Coq ProofDrift detectors use this function.
  The open obligation now says the implementation must change first.
- sigOnlySigner states that a matching key exists, not who signed;
  authenticity inherits that.
- The dispatch row notes that Unknown files with no adapter are marked
  unsupported and skipped before the match.
- The hexad property test's bounds are recorded from its generators.
- Stripping.idr: PROOF-NEEDS.md -> PROOF-NEEDS.adoc.

Stripping.idr still type-checks under Idris2 0.7.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jma5ixtpeZyJRmfoSsC98u
…ceipt

From CodeRabbit's second review, checked against analyzer.rs:

- The block-before-line ordering bug reaches every caller that passes
  both markers: analyze_rust, is_rust_ffi_safe_wrapper, analyze_idris,
  analyze_lean and analyze_agda. analyze_haskell does not call the
  function, and analyze_isabelle and analyze_coq pass no line marker.
  (The review listed Idris, Lean and Agda; the two Rust callers are
  affected too.)
- The receipt now records that Stripping.idr was rechecked after the
  comment-only edits in ab0fdb2. All five modules pass again under
  Idris2 0.7.0, and the diff from 3dc4728 touches only comment lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jma5ixtpeZyJRmfoSsC98u
Main took #281, which re-proved Stripping.idr and gated src/abi/ in CI
(idris-abi), and #275, which added a model-checked TLA+ entry.

- src/abi/Stripping.idr: main's re-proof. It states every theorem this
  branch's repair did, plus idempotence (stripLineCommentsIdempotent),
  stripIsIdOnClean, stripKeepsHead and two more sanity cases.
- src/abi/Types.idr: this branch's version (its header no longer claims
  theorems the module does not contain), plus main's doc line on Eq.
- PROOF-NEEDS.adoc: this branch's structure, with main's receipts
  paragraph, main's Stripping row text (it describes the file kept), main's
  TLA+ section and its Generation-publish obligation. The receipt section
  now names the idris-abi gate, which passed on main at 36f1055, and the
  open 'Gate the Idris2 modules in CI' row is removed because #281 did it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZnmBahbhfkFEP6ark4
The merge placed '||| Equality on severity' between 'public export' and
'Eq Severity where'. Idris2 then rejects 'public export' as a declaration
start (idris-abi on b332b5f). Doc comment first, as on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZnmBahbhfkFEP6ark4
Rebuild #282 on the flat src/abi/ layout that main keeps after #281.
Move the ABI modules back to src/abi/, drop the ipkg, and retire
PatternCompleteness.idr at its flat path. Point PROOF-PROGRAMME,
PROOF-NEEDS and EXPLAINME at src/assail/routing.rs for PA1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZnmBahbhfkFEP6ark4
Resolve PROOF-NEEDS.adoc in favour of this branch: main still carries
the PA1 rows from #277 (the vacuous PatternCompleteness model and the
"replace or retire PA1" open row), which this branch replaces with the
tested routing-table rows. cargo test --lib: 482 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0136P7ZnmBahbhfkFEP6ark4
@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

Caution

Review failed

The pull request is closed.

Summary

Summary by CodeRabbit

  • Bug Fixes
    • Updated analyzer routing so supported languages use their designated analyzers, with the generic analyzer reserved for languages without a dedicated route.
    • Cross-language checks now run on source files and embedded configuration scripts, but not on configuration content.
  • Documentation
    • Updated the README’s supported-language count and revised documentation describing analyzer routing and proof coverage.

The analyzer now dispatches through an exhaustive routing table. The change adds language inventory and routing tests, updates the documented language count to 51, and replaces the Idris2 PA1 completeness module with tested routing records and open proof obligations.

Changes: Analyzer Routing

Layer / File(s) Summary
Language inventory and routing table
src/types.rs, src/assail/routing.rs, src/assail/mod.rs
Language::ALL lists 52 variants, including Unknown. The new routing table maps languages to analyzer routes and maps routes to analyzer function names.
Route-based analysis
src/assail/analyzer.rs, src/assail/routing.rs
analyze_inner dispatches through routes. Cross-language checks run for non-configuration content and are skipped for configuration content.
Routing tests and PA1 records
src/assail/routing.rs, src/types.rs, README.adoc, 0-AI-MANIFEST.a2ml, EXPLAINME.adoc, PROOF-NEEDS.adoc, PROOF-PROGRAMME.adoc, src/abi/PatternCompleteness.idr
Tests cover route-to-analyzer reachability, fallback behaviour, cross-language selection, language-array ordering, and README counts. The documents record routing as tested, update the count to 51, and list remaining proof obligations. The Idris2 completeness module and its manifest entry are removed.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Analyzer as Analyzer::analyze_inner
  participant Router as route
  participant RouteMap as Route::analyzer
  participant Checks as Cross-language checks
  Analyzer->>Router: route(file_lang)
  Router-->>Analyzer: Route variant
  Analyzer->>RouteMap: select analyzer function
  RouteMap-->>Analyzer: analyzer function name
  Analyzer->>Checks: run checks when runs_cross_language(configuration.is_some()) is true
Loading

Possibly related PRs

Suggested reviewers: metadatastician

Merge Risk: Low · up to 71111

The change routes analyzers through a tested table and has no identified runtime regression. Some documentation still cites old language counts and overstates PA1 as proven, so fix those before or shortly after merging.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath marked this pull request as ready for review November 10, 2026 18:20
@hyperpolymath
hyperpolymath merged commit 681898c into main Nov 10, 2026
73 checks passed
@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-10T18:20:15.069633Z
We couldn’t complete this review. Comment @codex review to try again.
71111f9 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@hyperpolymath
hyperpolymath deleted the claude/pa1-routing-table branch November 10, 2026 18:20
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

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.

3 participants