M0+M1+M2: workspace, engine skeleton, T0 catalogue + falsifier gate - #19
Conversation
Pin all uses: references to full 40-char commit SHAs to prevent supply-chain attacks via mutable tags or branches. This resolves Scorecard Pinned-Dependencies alerts and Hypatia WH004 findings. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Pin all uses: references to full 40-char commit SHAs to prevent supply-chain attacks via mutable tags or branches. This resolves Scorecard Pinned-Dependencies alerts and Hypatia WH004 findings. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Replace local copy with call to hyperpolymath/cicd-suite workflow for single-source maintenance. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Virtual Cargo workspace (pons-core/pons-rules/pons-cli/pons-protocols) with the tree-sitter substrate smoke test (ADR-0001), plus M1's finding model (finding.rs), extension-to-grammar table (lang.rs), and recursive source discovery honouring .gitignore/.ponsignore (source.rs). Cargo.lock is committed deliberately, deviating from estate .gitignore norms: pons-cli builds a binary, so the lockfile is the correct Rust convention here, not dead weight. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2r6GWM6CYLgsSRDU386b3
Adds pons-core::engine (Rule/RuleCtx trait + orchestrating Engine), parse.rs (tree-sitter parse per Lang), the suppress.rs M7 stub, report::human (deterministic line output, with the fixed "(heuristic — not a verdict)" suffix demoting SPECULATIVE-tier findings, colour-independent since colour is lost in piped CI output), pons-rules::RuleRegistry (empty until M2's T0 catalogue), and real pons-cli wiring for `pons scan <path> [--fail-on <severity>]`. CLI exit-code contract per plan decision: 0 by default even with findings, 1 only via explicit --fail-on threshold, 2 for operational errors (bad path, scan failure); SPECULATIVE findings never trigger exit 1 regardless of threshold. M1 exit gate verified: `pons scan <dir>` runs end-to-end with zero rules registered, no panic, exit 0. cargo test --workspace: 17/17 passing (includes the SPECULATIVE-demotion unit test). clippy -D warnings and fmt --check both clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2r6GWM6CYLgsSRDU386b3
Adds the full T0 rule catalogue per docs/PLAN.adoc's M2 build order:
div-by-literal-zero, swallowed-error, self-assignment, constant-condition,
while-true-no-break, empty-effect-loop, unreachable-after-jump, and
string-concat-in-loop (no Rust variant — String += &str is amortised O(1)
there). Each rule ships tree-sitter .scm queries per language, a Rust
implementation with unit tests, and a fixtures/<rule-id>/{positive,negative}
corpus proven by the new pons-rules/tests/falsifier.rs gate (`just falsify`),
which also fails loudly on unresolvable fixture extensions and on any
declared language missing its own positive/negative fixture.
string-concat-in-loop's string-typed-RHS narrowing (needed so `count += 1`
never matches) fires when either the appended value itself contains a
string literal, or the accumulator was declared with a string initialiser
earlier in its enclosing scope — the latter is what makes the common
"append each loop item onto an accumulator string" shape detectable even
when the appended item is a plain identifier.
Also lands docs/adr/0005-cli-exit-code-contract.adoc (implemented in
pons-cli since the M1→M2 transition) and the Finding/RawFinding hardening
that preceded M2's rule files: private Finding fields with a wire-shadow
Deserialize that re-derives evidence from tier, and Rule::check returning
RawFinding (no rule_id) so only Engine::scan can stamp rule_id from
Rule::id().
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2r6GWM6CYLgsSRDU386b3
|
Important Review skippedToo many files! This PR contains 161 files, which is 61 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (161)
You can disable this status message by setting the 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. Comment |
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
|




Summary
Implements the ratified M0→M1→M2 milestones of
docs/PLAN.adoc:pons-core,pons-rules,pons-cli,pons-protocols), tree-sitter substrate smoke test across Python/JS/TS/TSX/Rust grammars, CI workflow, Justfile.Finding/RawFindingmodel (private fields,EvidenceClassderived fromTier, never trusted from wire),Rule/RuleCtxinpons-core::engine, human reporter with a colour-independent(heuristic — not a verdict)suffix forSPECULATIVEfindings,pons scanCLI wiring. CLI exit-code contract recorded asdocs/adr/0005-cli-exit-code-contract.adoc(exit 0 by default even with findings; opt-in--fail-on <severity>; exit 2 reserved for operational errors;SPECULATIVEfindings never trigger exit 1).div-by-literal-zero,swallowed-error,self-assignment,constant-condition,while-true-no-break,empty-effect-loop,unreachable-after-jump,string-concat-in-loop), each with per-language tree-sitter queries and a positive/negative fixture corpus, plus thepons-rules/tests/falsifier.rsgate that proves every rule against its own corpus (and fails loudly on unresolvable fixture extensions or a language declared by a rule with no fixture in that language).Note on branch history
This PR is opened from
feat/pons-m0-m2rather than the originally-plannedfeat/pons-m0-m1, because that local branch name had picked up an unrelated commit from a concurrent session (a workflow-campaign preservation commit whose own message says "NOT pushed").feat/pons-m0-m2is a clean cherry-pick of just the two pons commits (M1, M2) on top of the existing M0 commit — no.github/**changes, no overlap with that other work.Test plan
cargo build --workspacecargo test -p pons-core --test smokejust falsify(cargo test -p pons-rules --test falsifier)cargo test --workspacecargo clippy --workspace --all-targets -- -D warningscargo fmt --checkM3 (JSON/SARIF reporters, T1 dataflow, T2 typestate, T3 speculative rules, suppression) is out of scope for this PR.
🤖 Generated with Claude Code
https://claude.ai/code/session_01P2r6GWM6CYLgsSRDU386b3