/** * SMI-5879 Wave 3 item 2 — structural closure test for cohort E's exclusion * proof (design doc `smi-5879-edge-twin-parity-design.md` §8.3.1.2.2). * @module @skillsmith/core/security/scanner/multiline-category-closure.test * * WHY THIS TEST EXISTS * * The SMI-5879 census (comparing pre-port vs post-port `skills.security_score` * across ~344k rows) needs to fully re-simulate every row scoring `>= 8` * (cohort C1) but can structurally EXCLUDE every row scoring `0-7` (cohort E) * from that expensive re-simulation — *if and only if* three properties about * how the multiline pass routes patterns hold. The design doc's §8.3.1.2.1 * proves those properties in prose ("P1/P2/P3"); this file promotes that proof * to a machine-checked gate (design doc gate G-5) so a future source change * that silently invalidates the premise fails CI instead of silently * corrupting the census's soundness. * * THE +32 ARITHMETIC THIS TEST PROTECTS (not itself re-derived here — that is * `weights.ts` + the design doc's §8.3.1.2 arithmetic; this file only proves * the ROUTING facts the arithmetic depends on): * max joint contribution = 100 * CATEGORY_WEIGHTS.jailbreak.coefficient (0.20) * + 100 * CATEGORY_WEIGHTS.ai_defence.coefficient (0.12) * = 32.0 * S <= 7 => S' <= S + 32 <= 39 < 40 (QUARANTINE_THRESHOLD) => verdict * cannot flip to quarantined for any row starting at or below 7. * That bound is sound ONLY IF the multiline pass can never inflate any * category's subtotal OTHER than jailbreak / ai_defence. The three assertions * below are exactly what closes that "only if". * * THE DOCUMENTED TRAP (design doc §8.3.1.2.3) — DELIBERATELY NOT REPEATED HERE * * The design doc warns against writing assertion 3 as "every pattern for * which `isMultilinePattern()` returns true belongs to an AI-category array" * — that predicate is syntactic (it fires on a NEGATED class `[^\n]`, the * literal opposite of "spans lines") and is false today for 9 patterns across * two non-AI arrays. This file does not use that predicate at all: assertions * 1 and 3 are asserted over the multiline pass's CALL SITES (which pattern * array is physically wired to `scanPatternsWithMultilineSupport`'s `patterns:` * config field), not over any per-pattern syntactic test. That is the * "routing, not predicate" distinction the trap section requires. * * SMI-5881 ADAPTATION (judgment call — flagged, not silently resolved) * * The design doc's assertion 2 is written directly against `isMultilinePattern()` * as the definition of "PASS-1 pattern". SMI-5881 (merged before this file was * written) DELETED `isMultilinePattern()` entirely — no compatibility shim — * and replaced the syntactic heuristic with `PATTERN_SCOPE` / * `resolvePatternScope()` (`./patterns.scope.ts`), an explicit per-pattern * `'line' | 'content' | 'both'` declaration. `isMultilinePattern` cannot be * imported here; it no longer exists anywhere under `packages/core/src` * (guarded by `packages/core/tests/security/pattern-scope.test.ts`). * * `scanPatternsWithMultilineSupport`'s pass 1 (SecurityScanner.helpers.ts) now * reads: `if (resolvePatternScope(pattern) === 'line') continue` — i.e. pass 1 * tests every pattern whose resolved scope is NOT `'line'` (`'content'` or * `'both'`). That predicate is the faithful, current-source equivalent of the * design doc's `routed.filter(isMultilinePattern)` — same set membership * question ("which patterns does pass 1 actually read"), expressed against * the model that replaced the deleted one. Assertion 2 below uses * `resolvePatternScope(p) !== 'line'` for exactly this reason. * * CODE-REVIEW REMEDIATION (Finding 1 — NO-GO, fixed) * * A first version of this file enumerated call sites with a bounded * text-window regex scan (`CALL_TOKEN = 'scanPatternsWithMultilineSupport('` * + an `EXTRACTION_WINDOW`-char lookahead for `type:`/`patterns:`). Codex * (gpt-5.6-sol) review flagged that as a silent-false-negative hazard: a new * call site using extra whitespace before `(`, a locally-aliased identifier, * or a renamed import would be invisible to that regex while the existing two * call sites kept the count green — defeating the point of a closure proof * meant to catch exactly this class of drift. `extractMultilineCallSites` * below instead walks the real TypeScript AST (`ts.createSourceFile` + * `CallExpression` traversal resolved through `collectAliases`), which is * exhaustive by construction against all three variants. Verified via mutation * testing: a temporarily-added call through a whitespace-before-paren AND a * locally-aliased form was both correctly detected (count became 3, assertion * 1 failed) before being reverted. */ export {}; //# sourceMappingURL=multiline-category-closure.test.d.ts.map