@clear-capabilities/agentic-security-scanner 0.148.4 → 0.149.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- 9d52cc907c314d1ac60bc62b0c15a0ce4bbf28bdaeaa54a2e57782b9a75f97eb agentic-security.mjs
1
+ 080e8743db95f7b28cad5e33fe52383fe37a483d2c8bc0535bef1cfb3f9219e7 agentic-security.mjs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clear-capabilities/agentic-security-scanner",
3
- "version": "0.148.4",
3
+ "version": "0.149.0",
4
4
  "description": "Scanner engine for the agentic-security Claude Code plugin — SAST, SCA (function-level reachability + CISA KEV), secrets, IaC, prompt-injection, MCP/agent-tool audit, auth/authZ deep analysis, attack chains, PoC generation, business logic, toxic-combinations scoring, SBOM, pipeline integrity, compliance attestation, and more.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -64,8 +64,8 @@
64
64
  "test:smoke": "node --test test/smoke.test.js test/demo-app.test.js",
65
65
  "test:glob": "node --test test/glob-compat.test.js",
66
66
  "test:sast": "node --test test/cpp-hardcoded-secret.test.js test/sibling-guard.test.js test/comment-blindness.test.js test/crypto-specialist.test.js test/llm.test.js test/llm-cost-advisor.test.js test/llm-owasp.test.js test/logic.test.js test/authz.test.js test/model-load.test.js test/prompt-template.test.js test/business-logic.test.js test/python-sinks.test.js test/phase1-detectors.test.js test/phase2-detectors.test.js test/phase3-v3.test.js test/phase7-extensions.test.js test/phase8-extensions.test.js test/new-cwe-detectors.test.js test/file-upload.test.js test/llmsecops-detectors.test.js test/db-taint.test.js test/dart-swift.test.js test/zip-slip-containment-guard.test.js test/redos-anchoring.test.js test/path-guard-validator-call.test.js test/redos-nfa.test.js test/weak-randomness.test.js test/csharp-pipeline.test.js test/post-quantum-crypto.test.js test/web3-advanced.test.js test/cloud-iam-k8s.test.js test/crypto-protocol.test.js test/ml-supply-chain.test.js test/mcp-audit-scan.test.js test/wrong-context-sanitizer.test.js test/sanitizer-context.test.js test/frontend-hygiene.test.js test/csv-injection.test.js test/stored-taint.test.js test/tree-sitter-sinks.test.js test/kotlin-structural.test.js test/ruby-php-structural.test.js test/java-csharp-structural.test.js test/guard-recognition.test.js test/guard-window-identifier-correlation.test.js test/js-python-framework-structural.test.js test/go-structural.test.js test/secret-concat.test.js test/secret-redaction.test.js test/xss-reflected-multilang.test.js test/code-injection-multilang.test.js test/xxe-multilang.test.js test/xpath-injection-multilang.test.js test/gapfill-batch13.test.js test/agent-untrusted-flow.test.js test/api-authz.test.js test/event-entrypoint.test.js test/iac-terraform.test.js test/cross-service.test.js test/rbac-consistency.test.js test/adversarial-robustness.test.js test/secret-entropy.test.js test/comment-strip.test.js test/juliet-path-filter-gate.test.js test/java-bench-shape-opt-in.test.js test/reachability-missing-callgraph-data.test.js test/rate-limit.test.js test/auth-signals.test.js test/convention-deviation.test.js test/resource-exhaustion.test.js test/resource-exhaustion-realworld.test.js test/redirect-toctou.test.js test/redirect-toctou-realworld.test.js test/codegen-sink.test.js test/ownership-authz.test.js test/ownership-authz-realworld.test.js test/t21-precision-audit.test.js test/secrets-coverage.test.js test/prompt-injection-payloads.test.js test/iac-cloud-templates.test.js test/ruby-path-join.test.js test/sast/manifest-line-tracking.test.js",
67
- "test:posture": "node --test test/threat-model.test.js test/git-hardening.test.js test/privacy-framework.test.js test/material-change.test.js test/drift.test.js test/scorecard.test.js test/accuracy-scorecard.test.js test/scorecard-gate.test.js test/predeploy-gate.test.js test/release-check.test.js test/pre-push-gate.test.js test/dependency-currency.test.js test/package-contents-check.test.js test/gate-verdict-cache.test.js test/run-unit-tests.test.js test/release-workflow.test.js test/independent-population.test.js test/why-missed.test.js test/independent-scoring.test.js test/evidence-bundle.test.js test/obligation-evidence-pack.test.js test/policy-bundle.test.js test/discovery-memory.test.js test/mttr.test.js test/license-policy.test.js test/aibom.test.js test/sbom.test.js test/api-inventory.test.js test/iam-policy.test.js test/container.test.js test/container-runtime.test.js test/image-packages.test.js test/kev.test.js test/dep-confusion.test.js test/sca-deprecated.test.js test/sca-batch.test.js test/composite-risk.test.js test/epss-enrich.test.js test/sca-coverage.test.js test/gradle-deps.test.js test/sca-route-reachable.test.js test/sca-policy.test.js test/sca-verdict.test.js test/install-script.test.js test/sca-linked-findings.test.js test/packs.test.js test/flow-narration.test.js test/regression-test-gen.test.js test/deterministic-fix.test.js test/falsification.test.js test/verification-separation.test.js test/logic-claims.test.js test/attestation.test.js test/verify-attestation-cli.test.js test/comparison.test.js test/determinism-cross-machine.test.js test/fix-honesty-gate.test.js test/model-routing.test.js test/root-cause-sweep.test.js test/entrypoint-inventory.test.js test/relevance.test.js test/untrusted.test.js test/agent-hardening.test.js test/rule-synthesis.test.js test/policy-gate.test.js test/agents-memory.test.js test/cve-lookup.test.js test/cve-alert-daemon.test.js test/fix-verify-loop.test.js test/fix-verify-tests.test.js test/fix-acceptance.test.js test/exploitability-probability.test.js test/history-scan.test.js test/viral-features.test.js test/viral-v074.test.js test/state-dir.test.js test/ignore-pragma.test.js test/license-graph.test.js test/secret-live-check.test.js test/attack-taxonomy.test.js test/triage-memory.test.js test/pr-augment.test.js test/chat-batch2.test.js test/chat-batch3.test.js test/chat-batch4.test.js test/chat-batch5.test.js test/chat-batch6.test.js test/risk-scenario-disclosure.test.js test/egress-policy.test.js test/egress-policy-completeness.test.js test/egress-policy-integration.test.js test/router.test.js test/legacy-alias-redirect.test.js test/cache-economics.test.js test/coverage-report.test.js test/corpus-status.test.js test/provenance.test.js test/secret-history.test.js test/execution-proof.test.js test/fix-metrics.test.js test/corpus-enroll.test.js test/prove-findings.test.js test/corpus-match.test.js test/corpus-provenance.test.js test/learning-quorum.test.js test/llm-cache-integrity.test.js test/proof-artifact.test.js test/providers.test.js test/fleet.test.js test/autopilot.test.js test/autopilot-cli.test.js test/verifier-independence.test.js test/integrity-legacy-key.test.js test/suppression-visibility.test.js test/cost-ceiling.test.js test/local-endpoint.test.js test/model-trust.test.js test/vuln-archaeology.test.js test/scan-checkpoint.test.js test/llm-redact.test.js test/world-class-batch2.test.js test/world-class-modules.test.js test/privacy-ir-adapter.test.js test/privacy-taxonomy.test.js test/privacy-sink-policy.test.js test/privacy-governance.test.js test/privacy-inventory.test.js test/integration-end-to-end.test.js test/streak-cli-wiring.test.js test/stack-playbook.test.js test/machine-output-flag.test.js test/stdout-flush.test.js test/format-determinism.test.js test/only-flag-channels.test.js test/confidence.test.js test/security-trend.test.js test/calibration-drift.test.js test/validator-metrics.test.js test/clustering-ir-taint-line.test.js test/concurrency-cwe.test.js test/compliance-mapping-liveness.test.js test/module-artifact-liveness.test.js test/compliance-severity-threshold.test.js test/compliance-severity-policy.test.js test/compliance-evidence-binding.test.js test/compliance-evidence-signing.test.js test/compliance-file-contains.test.js test/label-isolation.test.js test/evidence-grade-wording.test.js test/llm-model-status.test.js test/egress-policy-constraints.test.js test/egress-redact.test.js test/egress-audit.test.js test/egress-approved-providers.test.js test/family-registry.test.js test/coverage-strength.test.js test/framework-provenance.test.js test/framework-provenance-controlrefs.test.js test/third-party-verification.test.js test/proof-coverage.test.js test/calibration-holdout.test.js test/independent-population-gate.test.js test/catalog-freshness.test.js test/incremental-parity.test.js test/surface-smoke.test.js test/fix-coverage.test.js test/raw-source-carveout.test.js test/mlbom-conformance.test.js test/deploy-gate-replay.test.js test/sbom-conformance.test.js test/unscored-claims.test.js test/mcp-rug-pull.test.js test/agent-boundary-taint.test.js test/confinement-adversarial.test.js test/comment-strip-cost.test.js test/reachability-claim.test.js test/entrypoint-breadth.test.js test/dep-file-admission.test.js test/custom-rules-freshness.test.js test/posture/provenance-schema.test.js test/posture/provenance-cache.test.js test/helpers/build-git-fixture.test.js test/posture/provenance-git-evidence.test.js test/posture/provenance-dag-walk.test.js test/posture/provenance-confidence.test.js test/posture/provenance-predicate-replay.test.js test/posture/provenance-origin-resolver.test.js test/posture/provenance-ai-authorship.test.js test/posture/provenance-branch-entry.test.js test/posture/provenance-evidence-attribution.test.js test/posture/provenance-lifecycle.test.js test/posture/provenance-missing-control-resolver.test.js test/posture/provenance-missing-control-wiring.test.js test/posture/provenance-coordinator.test.js test/posture/provenance-sca-origin.test.js test/posture/provenance-transitive-sca.test.js test/posture/provenance-coordinator-sca.test.js test/posture/provenance-providers.test.js test/posture/provenance-evidence-bundle.test.js test/posture/provenance-repo-lineage.test.js test/posture/provenance-secrets-logic.test.js test/cli/provenance-flags.test.js test/cli/attest-provenance.test.js test/cli/attest-obligations.test.js test/cli/compliance-walkthrough-lineage.test.js test/cli/dataflow-export-privacy.test.js test/cli/dataflow-export-briefing.test.js test/cli/lineage-snapshot-persist.test.js test/cli/dataflow-diff.test.js test/cli/dataflow-watch.test.js test/cli/dataflow-recipients.test.js test/cli/dataflow-coverage.test.js test/security/provenance-safety.test.js test/security/provenance-injection.test.js test/posture/remediation-ledger.test.js",
68
- "test:dataflow": "node --test test/privacy-catalog.test.js test/privacy-deep-walker.test.js test/privacy-deep-e2e.test.js test/container-taint.test.js test/stored-taint-families.test.js test/py-annotation-sources.test.js test/fn-reach.test.js test/deep-taint.test.js test/calibration.test.js test/holdout-eval.test.js test/cross-lang-meta.test.js test/cross-lang-queues.test.js test/phase5-xlang.test.js test/phase5-coverage.test.js test/phase6-taint.test.js test/llm-validator-consistency.test.js test/llm-validator-default-on.test.js test/llm-validator-preset.test.js test/parser-py-cst.test.js test/chrome-probe.test.js test/parser-cs-kt.test.js test/parser-cs-annotations.test.js test/parser-cs-control-flow.test.js test/parser-kt-control-flow.test.js test/parser-js-annotations.test.js test/parser-java-annotations.test.js test/parser-java-control-flow.test.js test/parser-java-calls.test.js test/parser-go.test.js test/parser-php-rb.test.js test/parser-php-control-flow.test.js test/interproc-k2.test.js test/proven-clean.test.js test/backward-default.test.js test/incremental-cache.test.js test/string-regex-lattice.test.js test/closure-capture.test.js test/points-to.test.js test/type-stubs.test.js test/soft-taint.test.js test/ifds.test.js test/symbolic-exec-proof.test.js test/ifds-summary-edges.test.js test/stub-aware-filter.test.js test/cross-repo.test.js test/proof-gate.test.js test/layer-recall.test.js test/java-taint-flow.test.js test/kt-taint-flow.test.js test/sanitizer-typed-flow.test.js test/sanitizer-gate-unit.test.js test/proof-safe.test.js test/collection-taint.test.js test/kcfa-context.test.js test/kcfa-callstring.test.js test/flow-parity.test.js test/callgraph-resolve.test.js test/import-reachability.test.js test/ir-stats.test.js test/parser-cpp.test.js test/parser-js-decorators.test.js test/parser-js-if-else-cfg.test.js test/cpp-integration.test.js test/engine-reconnect.test.js test/phase2-scoping.test.js test/engine-recall.test.js test/catalog-annotation-source.test.js test/catalog-cs-p1.test.js test/catalog-expanded.test.js test/builtin-summaries.test.js test/interproc-mutation-crash.test.js test/mutated-param-taint.test.js test/return-sink-check.test.js test/higher-order-inline-callback.test.js test/interproc-findings-discard.test.js test/runscan-deep-option.test.js test/summary-cache-convergence.test.js test/parser-rb-calls.test.js test/parser-rb-module-level.test.js test/balanced-call.test.js test/destructuring-taint.test.js test/computed-member-taint.test.js test/string-interpolation-taint.test.js test/dataflow-deadcode-severity.test.js test/catalog-dotted-callee-lookup.test.js test/builtin-summary-family-blind-kill.test.js test/deep-mode-annotator-pipeline.test.js test/receiver-type-and-nested-calls.test.js test/member-write-and-loop-taint.test.js test/parser-py-module-level.test.js test/parser-php-module-level.test.js test/r14b-module-level-e2e.test.js test/annotation-taint-engine.test.js test/interproc-nested-call-taint.test.js test/catalog-xpath-injection.test.js test/catalog-ldap-injection.test.js test/catalog-xxe.test.js test/catalog-response-splitting.test.js test/catalog-code-injection.test.js test/parser-rb-control-flow.test.js test/catalog-ruby-p1.test.js test/callee-receiver-taint.test.js test/catalog-command-injection-p4.test.js test/catalog-xss-p4.test.js test/catalog-path-ssrf-p3.test.js test/catalog-ai-model-provider-precision.test.js test/catalog-orm-write.test.js test/dataflow/provenance-pipeline-integration.test.js",
67
+ "test:posture": "node --test test/threat-model.test.js test/git-hardening.test.js test/privacy-framework.test.js test/material-change.test.js test/drift.test.js test/scorecard.test.js test/accuracy-scorecard.test.js test/scorecard-gate.test.js test/predeploy-gate.test.js test/release-check.test.js test/pre-push-gate.test.js test/dependency-currency.test.js test/package-contents-check.test.js test/gate-verdict-cache.test.js test/run-unit-tests.test.js test/release-workflow.test.js test/independent-population.test.js test/why-missed.test.js test/independent-scoring.test.js test/evidence-bundle.test.js test/obligation-evidence-pack.test.js test/policy-bundle.test.js test/discovery-memory.test.js test/mttr.test.js test/license-policy.test.js test/aibom.test.js test/sbom.test.js test/api-inventory.test.js test/iam-policy.test.js test/container.test.js test/container-runtime.test.js test/image-packages.test.js test/kev.test.js test/dep-confusion.test.js test/sca-deprecated.test.js test/sca-batch.test.js test/composite-risk.test.js test/epss-enrich.test.js test/sca-coverage.test.js test/gradle-deps.test.js test/sca-route-reachable.test.js test/sca-policy.test.js test/sca-verdict.test.js test/install-script.test.js test/sca-linked-findings.test.js test/packs.test.js test/flow-narration.test.js test/regression-test-gen.test.js test/deterministic-fix.test.js test/falsification.test.js test/verification-separation.test.js test/logic-claims.test.js test/attestation.test.js test/verify-attestation-cli.test.js test/comparison.test.js test/determinism-cross-machine.test.js test/fix-honesty-gate.test.js test/model-routing.test.js test/root-cause-sweep.test.js test/entrypoint-inventory.test.js test/relevance.test.js test/untrusted.test.js test/agent-hardening.test.js test/rule-synthesis.test.js test/policy-gate.test.js test/agents-memory.test.js test/cve-lookup.test.js test/cve-alert-daemon.test.js test/fix-verify-loop.test.js test/fix-verify-tests.test.js test/fix-acceptance.test.js test/exploitability-probability.test.js test/history-scan.test.js test/viral-features.test.js test/viral-v074.test.js test/state-dir.test.js test/ignore-pragma.test.js test/license-graph.test.js test/secret-live-check.test.js test/attack-taxonomy.test.js test/triage-memory.test.js test/pr-augment.test.js test/chat-batch2.test.js test/chat-batch3.test.js test/chat-batch4.test.js test/chat-batch5.test.js test/chat-batch6.test.js test/risk-scenario-disclosure.test.js test/egress-policy.test.js test/egress-policy-completeness.test.js test/egress-policy-integration.test.js test/router.test.js test/legacy-alias-redirect.test.js test/cache-economics.test.js test/coverage-report.test.js test/corpus-status.test.js test/provenance.test.js test/secret-history.test.js test/execution-proof.test.js test/fix-metrics.test.js test/corpus-enroll.test.js test/prove-findings.test.js test/corpus-match.test.js test/corpus-provenance.test.js test/learning-quorum.test.js test/llm-cache-integrity.test.js test/proof-artifact.test.js test/providers.test.js test/fleet.test.js test/autopilot.test.js test/autopilot-cli.test.js test/verifier-independence.test.js test/integrity-legacy-key.test.js test/suppression-visibility.test.js test/cost-ceiling.test.js test/local-endpoint.test.js test/model-trust.test.js test/vuln-archaeology.test.js test/scan-checkpoint.test.js test/llm-redact.test.js test/world-class-batch2.test.js test/world-class-modules.test.js test/privacy-ir-adapter.test.js test/privacy-taxonomy.test.js test/privacy-sink-policy.test.js test/privacy-governance.test.js test/privacy-inventory.test.js test/integration-end-to-end.test.js test/streak-cli-wiring.test.js test/stack-playbook.test.js test/machine-output-flag.test.js test/stdout-flush.test.js test/format-determinism.test.js test/only-flag-channels.test.js test/confidence.test.js test/security-trend.test.js test/calibration-drift.test.js test/validator-metrics.test.js test/clustering-ir-taint-line.test.js test/concurrency-cwe.test.js test/compliance-mapping-liveness.test.js test/module-artifact-liveness.test.js test/supply-chain-provenance-completeness.test.js test/compliance-severity-threshold.test.js test/compliance-severity-policy.test.js test/compliance-evidence-binding.test.js test/compliance-evidence-signing.test.js test/compliance-file-contains.test.js test/label-isolation.test.js test/evidence-grade-wording.test.js test/llm-model-status.test.js test/egress-policy-constraints.test.js test/egress-redact.test.js test/egress-audit.test.js test/egress-approved-providers.test.js test/family-registry.test.js test/coverage-strength.test.js test/framework-provenance.test.js test/framework-provenance-controlrefs.test.js test/third-party-verification.test.js test/proof-coverage.test.js test/calibration-holdout.test.js test/independent-population-gate.test.js test/catalog-freshness.test.js test/incremental-parity.test.js test/surface-smoke.test.js test/fix-coverage.test.js test/raw-source-carveout.test.js test/mlbom-conformance.test.js test/deploy-gate-replay.test.js test/sbom-conformance.test.js test/unscored-claims.test.js test/mcp-rug-pull.test.js test/agent-boundary-taint.test.js test/confinement-adversarial.test.js test/comment-strip-cost.test.js test/reachability-claim.test.js test/entrypoint-breadth.test.js test/dep-file-admission.test.js test/custom-rules-freshness.test.js test/posture/provenance-schema.test.js test/posture/provenance-cache.test.js test/helpers/build-git-fixture.test.js test/posture/provenance-git-evidence.test.js test/posture/provenance-dag-walk.test.js test/posture/provenance-confidence.test.js test/posture/provenance-predicate-replay.test.js test/posture/provenance-origin-resolver.test.js test/posture/provenance-ai-authorship.test.js test/posture/provenance-branch-entry.test.js test/posture/provenance-evidence-attribution.test.js test/posture/provenance-lifecycle.test.js test/posture/provenance-missing-control-resolver.test.js test/posture/provenance-missing-control-wiring.test.js test/posture/provenance-coordinator.test.js test/posture/provenance-sca-origin.test.js test/posture/provenance-transitive-sca.test.js test/posture/provenance-coordinator-sca.test.js test/posture/provenance-providers.test.js test/posture/provenance-evidence-bundle.test.js test/posture/provenance-repo-lineage.test.js test/posture/provenance-secrets-logic.test.js test/cli/provenance-flags.test.js test/cli/attest-provenance.test.js test/cli/attest-obligations.test.js test/cli/compliance-walkthrough-lineage.test.js test/cli/dataflow-export-privacy.test.js test/cli/dataflow-export-briefing.test.js test/cli/lineage-snapshot-persist.test.js test/cli/dataflow-diff.test.js test/cli/dataflow-watch.test.js test/cli/dataflow-recipients.test.js test/cli/dataflow-coverage.test.js test/security/provenance-safety.test.js test/security/provenance-injection.test.js test/posture/remediation-ledger.test.js",
68
+ "test:dataflow": "node --test test/privacy-catalog.test.js test/privacy-deep-walker.test.js test/privacy-deep-e2e.test.js test/container-taint.test.js test/stored-taint-families.test.js test/py-annotation-sources.test.js test/fn-reach.test.js test/deep-taint.test.js test/calibration.test.js test/holdout-eval.test.js test/cross-lang-meta.test.js test/cross-lang-queues.test.js test/phase5-xlang.test.js test/phase5-coverage.test.js test/phase6-taint.test.js test/llm-validator-consistency.test.js test/llm-validator-default-on.test.js test/llm-validator-preset.test.js test/parser-py-cst.test.js test/chrome-probe.test.js test/parser-cs-kt.test.js test/parser-cs-annotations.test.js test/parser-cs-control-flow.test.js test/parser-kt-control-flow.test.js test/parser-js-annotations.test.js test/parser-java-annotations.test.js test/parser-java-control-flow.test.js test/parser-java-calls.test.js test/parser-go.test.js test/parser-php-rb.test.js test/parser-php-control-flow.test.js test/interproc-k2.test.js test/proven-clean.test.js test/backward-default.test.js test/incremental-cache.test.js test/string-regex-lattice.test.js test/closure-capture.test.js test/points-to.test.js test/type-stubs.test.js test/soft-taint.test.js test/ifds.test.js test/symbolic-exec-proof.test.js test/ifds-summary-edges.test.js test/stub-aware-filter.test.js test/cross-repo.test.js test/proof-gate.test.js test/layer-recall.test.js test/java-taint-flow.test.js test/kt-taint-flow.test.js test/sanitizer-typed-flow.test.js test/sanitizer-gate-unit.test.js test/proof-safe.test.js test/collection-taint.test.js test/kcfa-context.test.js test/kcfa-callstring.test.js test/flow-parity.test.js test/callgraph-resolve.test.js test/import-reachability.test.js test/ir-stats.test.js test/parser-cpp.test.js test/parser-js-decorators.test.js test/parser-js-if-else-cfg.test.js test/cpp-integration.test.js test/engine-reconnect.test.js test/phase2-scoping.test.js test/engine-recall.test.js test/catalog-annotation-source.test.js test/catalog-cs-p1.test.js test/catalog-expanded.test.js test/builtin-summaries.test.js test/interproc-mutation-crash.test.js test/mutated-param-taint.test.js test/return-sink-check.test.js test/higher-order-inline-callback.test.js test/interproc-findings-discard.test.js test/runscan-deep-option.test.js test/summary-cache-convergence.test.js test/parser-rb-calls.test.js test/parser-rb-module-level.test.js test/balanced-call.test.js test/destructuring-taint.test.js test/computed-member-taint.test.js test/string-interpolation-taint.test.js test/dataflow-deadcode-severity.test.js test/catalog-dotted-callee-lookup.test.js test/builtin-summary-family-blind-kill.test.js test/deep-mode-annotator-pipeline.test.js test/receiver-type-and-nested-calls.test.js test/member-write-and-loop-taint.test.js test/parser-py-module-level.test.js test/parser-php-module-level.test.js test/r14b-module-level-e2e.test.js test/annotation-taint-engine.test.js test/interproc-nested-call-taint.test.js test/catalog-xpath-injection.test.js test/catalog-ldap-injection.test.js test/catalog-xxe.test.js test/catalog-response-splitting.test.js test/catalog-code-injection.test.js test/parser-rb-control-flow.test.js test/catalog-ruby-p1.test.js test/callee-receiver-taint.test.js test/catalog-command-injection-p4.test.js test/catalog-xss-p4.test.js test/catalog-path-ssrf-p3.test.js test/catalog-ai-model-provider-precision.test.js test/catalog-orm-write.test.js test/dataflow/provenance-pipeline-integration.test.js test/dataflow-progress.test.js test/scan-progress.test.js",
69
69
  "test:mcp": "node --test test/mcp.test.js test/mcp-protocol-smoke.test.js test/mcp-audit.test.js test/audit-cli.test.js test/mcp-scratchpad.test.js test/mcp-offload.test.js test/sca-upgrade.test.js test/lsp-server.test.js test/mcp-dataflow-tools.test.js test/cli/governance-propose-edit.test.js test/cli/remediation-open-update.test.js test/cli/remediation-verify-reopen.test.js test/cli/dataflow-observations.test.js test/cli/federate-declare-list.test.js",
70
70
  "test:report": "node --test test/report-scan-invariants.test.js test/junit.test.js test/ci.test.js test/poc-generator.test.js test/verifier.test.js test/verifier-target.test.js test/annotator-errors.test.js test/scan-health.test.js test/finding-schema.test.js test/pipeline/finding-schema-provenance.test.js test/evidence-provenance.test.js test/report/provenance-output.test.js test/report/provenance-format-parity.test.js test/legacy-compat.test.js test/annotator-runner.test.js test/detector-runner.test.js test/detector-errors.test.js test/analyzer-supervisor.test.js test/cascade-worker-pool.test.js test/cascade-pool-wiring.test.js test/coverage-ledger.test.js test/coverage-ledger-completeness.test.js test/assurance-mode.test.js test/artifact-registry.test.js test/artifact-registry-completeness.test.js test/retention-policy.test.js test/state-lifecycle-report.test.js test/legal-hold.test.js test/production-feedback.test.js test/calibration-feedback.test.js test/encryption-provider.test.js test/grader-calibration.test.js test/pr-delta-gate.test.js test/vex.test.js test/report-render.test.js test/oscal-conformance.test.js test/cli-fix-apply.test.js test/apply-fix-service.test.js test/high-impact-approval-gate.test.js test/approver-registry.test.js test/suppression-exceptions.test.js test/fix-history.test.js test/producer-registry.test.js test/producer-collector.test.js test/enrichment-completion.test.js",
71
71
  "test:lineage": "node --test test/lineage/schema.test.js test/lineage/ids.test.js test/lineage/protection.test.js test/lineage/classification.test.js test/lineage/validate.test.js test/lineage/json-schema-parity.test.js test/lineage/flagship-fixture.test.js test/lineage/flagship-fixture-semantics.test.js test/lineage/field-identity.test.js test/lineage/engine-expr-resolver.test.js test/lineage/engine-walker.test.js test/lineage/engine-integration.test.js test/lineage/engine-receiver-identity.test.js test/lineage/summaries.test.js test/lineage/driver.test.js test/lineage/engine-provenance.test.js test/lineage/engine-provenance-interprocedural.test.js test/lineage/path-store.test.js test/lineage/path-query.test.js test/lineage/flow-grade.test.js test/lineage/source-registry.test.js test/lineage/sink-registry.test.js test/lineage/transform-catalog.test.js test/lineage/handling-analyzer.test.js test/lineage/registry-real-code.test.js test/lineage/source-seeding.test.js test/lineage/graph-builder.test.js test/lineage/coverage.test.js test/lineage/resolve-destination.test.js test/lineage/queue-detail.test.js test/lineage/index.test.js test/lineage/obligation-mapping.test.js test/lineage/obligation-predicates.test.js test/lineage/obligation-predicates-walkthrough.test.js test/lineage/transit-protection.test.js test/lineage/at-rest-protection.test.js test/lineage/protection-summary.test.js test/lineage/ac01-multi-sink.test.js test/lineage/policy-verdict.test.js test/lineage/governance-refs.test.js test/lineage/export-privacy.test.js test/lineage/export-json.test.js test/lineage/export-csv.test.js test/lineage/decision-story.test.js test/lineage/export-briefing.test.js test/lineage/graph-snapshot.test.js test/lineage/graph-diff.test.js test/lineage/drift-policy.test.js test/lineage/recipient-profile.test.js test/lineage/recipient-registry.test.js test/lineage/recipient-wiring.test.js test/lineage/redact-graph.test.js test/lineage-scan-wiring.test.js test/lineage-artifact-write.test.js test/bench-data-lineage-runner.test.js test/bundle-frontend.test.js test/bundle-frontend-golden.test.js test/generate-html-report.test.js test/export-image.test.js test/lineage/scenario.test.js test/lineage/scenario-engine.test.js test/lineage/scenario-diff.test.js test/lineage/scenario-no-obligation-wiring.test.js test/lineage/impact-assessment.test.js test/lineage/impact-engine.test.js test/lineage/impact-no-obligation-wiring.test.js test/lineage/governance-edit.test.js test/lineage/remediation.test.js test/lineage/runtime-observation.test.js test/lineage/observation-correlation.test.js test/lineage/observation-adapters.test.js test/lineage/observation-store.test.js test/lineage/runtime-corroboration-wiring.test.js test/lineage/cross-repo-link.test.js test/lineage/federation-loader.test.js test/lineage/cross-repo-link-wiring.test.js",
@@ -1492,6 +1492,18 @@ export function runTaintEngine(perFileIR, callGraph, opts = {}) {
1492
1492
  const fnLimit = opts.fnLimit || 5000;
1493
1493
  const deadlineMs = typeof opts.deadlineMs === 'number' ? opts.deadlineMs : Infinity;
1494
1494
  let n = 0;
1495
+ // Live progress for this engine's dominant per-function loop (below,
1496
+ // bounded by fnLimit) — the longest-running phase of a deep scan on any
1497
+ // real-sized project. Additive/opt-in: with no `opts.onProgress`, nothing
1498
+ // here runs and every existing caller is byte-identical to before this
1499
+ // existed. Only the pre-passes above (fixed-point empty-entry pre-pass,
1500
+ // class-field cross-taint pass, k=2 pass) are NOT instrumented — they run
1501
+ // before `fnList.length` is known to be the final total below, and adding
1502
+ // per-iteration reporting to all four loops was judged disproportionate
1503
+ // risk to this engine's own worklist for the UX gain; the operator sees
1504
+ // the phase-start message the caller prints before this function is ever
1505
+ // invoked, then live per-function progress once this loop begins.
1506
+ const onProgress = typeof opts.onProgress === 'function' ? opts.onProgress : null;
1495
1507
 
1496
1508
  // Premortem #7: instantiate the k=1 SummaryCache and seed it with each
1497
1509
  // function's empty-entry-state summary (returnTainted bit). The cache is
@@ -1666,9 +1678,11 @@ export function runTaintEngine(perFileIR, callGraph, opts = {}) {
1666
1678
  findings: ctx._findings,
1667
1679
  });
1668
1680
  }
1681
+ const _progressTotal = Math.min(fnList.length, fnLimit);
1669
1682
  for (const fn of fnList) {
1670
1683
  if (++n > fnLimit) break;
1671
1684
  if (Date.now() > deadlineMs) break; // global timeout
1685
+ if (onProgress) onProgress({ current: n, total: _progressTotal });
1672
1686
  // Module-level functions: analyze with an empty entry state. The function
1673
1687
  // discovers its own sources from req.body/process.env/etc. as it walks.
1674
1688
  const callContext = {
package/src/engine.js CHANGED
@@ -721,6 +721,19 @@ const AUTH_PATTERNS=[/(?:authenticate|isAuthenticated|requireAuth|passport\.auth
721
721
  // output becomes input.
722
722
  const IGNORE_DIRS=new Set(["node_modules",".git","__pycache__","vendor","dist","build",".next","venv","env",".venv","target","bin","obj",".cache","coverage","bower_components","tests","test","__tests__","spec","mocks",".agentic-security"]);
723
723
  const CODE_EXTS=new Set(["js","jsx","ts","tsx","mjs","cjs","py","rb","php","java","go","cs","rs","vue","svelte","html","htm","ejs","hbs","pug","erb","twig","graphql","gql","kt","scala","swift","dart","ex","exs","tf","tfvars","dockerfile","c","cc","cpp","cxx","h","hh","hpp","hxx","sol"]);
724
+ // Supply-chain finding types that genuinely describe an ABSENT declaration
725
+ // (no origin commit exists to resolve — see the provenance-stamping loop
726
+ // later in this file for the full reasoning). Hoisted to module scope and
727
+ // exported via `_internals` (S4, adversarial premortem third pass,
728
+ // 2026-09-07) so `test/supply-chain-provenance-completeness.test.js` can
729
+ // assert every OTHER supply-chain finding type this file produces is either
730
+ // a member here or is a real source-location type (cdn_no_integrity,
731
+ // dynamic_require) — without that guard, a future type added to one
732
+ // detection loop and forgotten in this Set silently tells a user a
733
+ // genuinely-unresolvable absence is an ordinary, fixable coverage gap, the
734
+ // exact wrong-direction error the third premortem pass flagged as a
735
+ // maintainability risk even though today's two-member Set is correct.
736
+ const SUPPLY_CHAIN_ABSENCE_TYPES = new Set(['unpinned_dep', 'no_lockfile']);
724
737
  // Feat-2: IaC manifest filenames that aren't extension-based.
725
738
  const IAC_FILENAMES = new Set(['Dockerfile', 'Containerfile', 'docker-compose.yml', 'docker-compose.yaml', 'Chart.yaml']);
726
739
  function _isIaCFile(p){
@@ -9198,12 +9211,23 @@ function _deterministicFileTimings(timings) {
9198
9211
  // deadlineMs hint that the inner loops check; if absent, we still cap
9199
9212
  // function count via fnLimit. Operators who suspect a hung run can
9200
9213
  // kill the process and re-run with AGENTIC_SECURITY_DEEP=0.
9214
+ setProgress({ phase: 'Deep analysis', current: 0, total: 0, file: `starting (budget ${Math.round(budgetMs / 1000)}s)` });
9201
9215
  const irFindings = runDeepAnalysis(perFile, callGraph, {
9202
9216
  fnLimit: parseInt(process.env.AGENTIC_SECURITY_DEEP_FN_LIMIT || '5000', 10),
9203
9217
  deadlineMs: t0 + budgetMs,
9204
9218
  // v0.69 — incremental cache inputs (used when AGENTIC_SECURITY_INCREMENTAL=1).
9205
9219
  scanRoot,
9206
9220
  fileContents: fc,
9221
+ // Live per-function progress from the engine's own dominant loop
9222
+ // (dataflow/engine.js's runTaintEngine) — the pre-passes before it
9223
+ // (fixed-point pre-pass, class-field pass, k=2 pass) aren't
9224
+ // individually instrumented (see that file's own onProgress
9225
+ // comment), so the terminal shows the "starting" message above
9226
+ // until this loop begins, then live current/total from here on.
9227
+ onProgress: (p) => setProgress({
9228
+ phase: 'Deep analysis', current: p.current, total: p.total,
9229
+ file: `${Math.round((Date.now() - t0) / 1000)}s elapsed`,
9230
+ }),
9207
9231
  });
9208
9232
  const elapsed = Date.now() - t0;
9209
9233
  if (elapsed > budgetMs) {
@@ -9289,7 +9313,15 @@ function _deterministicFileTimings(timings) {
9289
9313
  // if deep mode already built it, this is free; if not, this is what
9290
9314
  // first triggers the build (the whole reason this gate is independent).
9291
9315
  const { perFile, callGraph } = _sharedIR || (_sharedIR = await _buildIR());
9316
+ const _lineageT0 = Date.now();
9317
+ setProgress({ phase: 'Lineage graph', current: 0, total: 0, file: `starting (budget ${Math.round(_lineageBudgetMs / 1000)}s)` });
9292
9318
  const _lr = buildLineageGraph(callGraph, {
9319
+ // Live per-function progress from the field-identity driver's own
9320
+ // single pass over every function (src/lineage/driver.js).
9321
+ onProgress: (p) => setProgress({
9322
+ phase: 'Lineage graph', current: p.current, total: p.total,
9323
+ file: `${Math.round((Date.now() - _lineageT0) / 1000)}s elapsed`,
9324
+ }),
9293
9325
  // scanRoot can be null (e.g. an MCP scan_diff caller, or
9294
9326
  // runFullScan invoked directly with no scanRoot) — fall back to
9295
9327
  // undefined rather than inventing a repository name from the
@@ -9567,7 +9599,22 @@ function _deterministicFileTimings(timings) {
9567
9599
  // since this project's own annotators are deliberately built never to
9568
9600
  // throw (posture/CLAUDE.md's "no throwing" convention) — this closure just
9569
9601
  // supplies the local _annotatorErrors array.
9570
- const _runAnnotator = (phase, fn) => runAnnotatorAsync(_annotatorErrors, phase, fn);
9602
+ // Live progress for this whole annotator sequence (~52 `await
9603
+ // _runAnnotator(...)` call sites below, re-derive via `grep -c "await
9604
+ // _runAnnotator(" src/engine.js` rather than trusting this count to stay
9605
+ // current) — previously silent even though it can take a real fraction of
9606
+ // scan time on a large finding set. `_ANNOTATOR_TOTAL_ESTIMATE` is an
9607
+ // upper bound, not an exact count: several call sites below are
9608
+ // conditional (deep-mode-only, provenance-only, etc.), so a real scan
9609
+ // reports fewer steps than the total and the progress bar does not
9610
+ // necessarily reach it — that's the same "stale total, real motion" shape
9611
+ // the pre-existing "Linking" phase already accepts.
9612
+ const _ANNOTATOR_TOTAL_ESTIMATE = 52;
9613
+ let _annotatorIdx = 0;
9614
+ const _runAnnotator = (phase, fn) => {
9615
+ setProgress({ phase: 'Annotating', current: ++_annotatorIdx, total: _ANNOTATOR_TOTAL_ESTIMATE, file: phase });
9616
+ return runAnnotatorAsync(_annotatorErrors, phase, fn);
9617
+ };
9571
9618
  await _runAnnotator('annotateStableIds', () => annotateStableIds(finalFindings));
9572
9619
  await _runAnnotator("clusterByRootCause", () => { finalFindings = clusterByRootCause(finalFindings); });
9573
9620
  await _runAnnotator("demoteUnreachable", () => {
@@ -10652,7 +10699,7 @@ function _deterministicFileTimings(timings) {
10652
10699
  // The first three are honest `not_available` — that is exactly what the
10653
10700
  // status is for. Only a genuine annotator failure is an `error`, which is
10654
10701
  // why this loop distinguishes them rather than stamping one status for all.
10655
- const SUPPLY_CHAIN_ABSENCE_TYPES = new Set(['unpinned_dep', 'no_lockfile']);
10702
+ // (SUPPLY_CHAIN_ABSENCE_TYPES is module-scoped see its own comment.)
10656
10703
  for (const sc of (supplyChain || [])) {
10657
10704
  if (!sc || typeof sc !== 'object' || sc.findingProvenance) continue;
10658
10705
  let limitation;
@@ -11239,4 +11286,5 @@ export {
11239
11286
  /** Internals exposed for targeted unit tests (not part of the public API). */
11240
11287
  export const _internals = {
11241
11288
  _isLikelyUnsafeRegex, _isAnchoredRegex, _hasNestedQuantifier, _extractRegexLiterals, _hasLeadingUnboundedQuantifier,
11289
+ SUPPLY_CHAIN_ABSENCE_TYPES,
11242
11290
  };
@@ -66,9 +66,17 @@ export function runFieldIdentityAnalysis(callGraph, opts = {}) {
66
66
  const fnList = callGraph && callGraph.functions
67
67
  ? [...callGraph.functions.values()].sort((a, b) => (a.qid < b.qid ? -1 : a.qid > b.qid ? 1 : 0))
68
68
  : [];
69
+ // Live progress, additive/opt-in — mirrors dataflow/engine.js's own
70
+ // `runTaintEngine` onProgress precedent exactly. Unlike that engine, this
71
+ // driver has only ONE pass over `fnList` (no fixed-point pre-passes), so
72
+ // every function this driver analyzes is reported, not just a dominant
73
+ // subset.
74
+ const onProgress = typeof opts.onProgress === 'function' ? opts.onProgress : null;
75
+ let _progressN = 0;
69
76
 
70
77
  const results = new Map();
71
78
  for (const fn of fnList) {
79
+ if (onProgress) onProgress({ current: ++_progressN, total: fnList.length });
72
80
  const lookupCallee = createCallGraphLookup(callGraph, fn.file);
73
81
  const resolveCallSummary = createCallSummaryResolver(cache, lookupCallee);
74
82
  // Path provenance (Sub-project C, increment 3, §13.7 item 14): thread
@@ -440,6 +440,7 @@ export function buildDataFlowGraph(callGraph, opts = {}) {
440
440
  recordHop: (h) => hops.push(h),
441
441
  seedEntryState: seedEntryStateFactory(seeds),
442
442
  ...(opts.maxContextsPerFn === undefined ? {} : { maxContextsPerFn: opts.maxContextsPerFn }),
443
+ ...(opts.onProgress ? { onProgress: opts.onProgress } : {}),
443
444
  });
444
445
  const store = new PathStore();
445
446
  store.addHops(hops);
@@ -271,6 +271,7 @@ export function buildLineageGraph(callGraph, opts = {}) {
271
271
  crossRepoLinkRecords,
272
272
  observationWindowStart: opts.observationWindowStart,
273
273
  observationWindowEnd: opts.observationWindowEnd,
274
+ onProgress: opts.onProgress,
274
275
  });
275
276
  return { status: 'complete', graph: built.graph, transitEvidence, failure: null, elapsedMs: Date.now() - t0 };
276
277
  } catch (e) {
@@ -95,10 +95,19 @@ function _provenanceFailureReason(badProvenance, totalFindings) {
95
95
  // gap was an unfixable, by-design limitation).
96
96
  const supplyChainReasons = ranked.filter(([r]) => r.startsWith('origin resolution does not apply to a'));
97
97
  const supplyChainCount = supplyChainReasons.reduce((s, [, n]) => s + n, 0);
98
- const knownReasonSet = new Set([...gitReasons, ...supplyChainReasons].map(([r]) => r));
98
+ // Third known bucket (S1, adversarial premortem third pass, 2026-09-07):
99
+ // cdn_no_integrity/dynamic_require's "not yet wired" string (see the
100
+ // engine.js comment this file's `supplyChainReasons` block already
101
+ // references) was previously falling through to the generic `otherReasons`
102
+ // path below — honest, but verbose, and with no recommended next step,
103
+ // unlike every other named bucket here. Giving it its own bucket closes
104
+ // that inconsistency without touching the two already-fixed buckets.
105
+ const notYetWiredReasons = ranked.filter(([r]) => r.startsWith('origin resolution is not yet wired for a'));
106
+ const notYetWiredCount = notYetWiredReasons.reduce((s, [, n]) => s + n, 0);
107
+ const knownReasonSet = new Set([...gitReasons, ...supplyChainReasons, ...notYetWiredReasons].map(([r]) => r));
99
108
  const otherReasons = ranked.filter(([r]) => !knownReasonSet.has(r));
100
- const otherCount = badProvenance.length - gitCount - supplyChainCount;
101
- const knownCategoryCount = (gitCount > 0 ? 1 : 0) + (supplyChainCount > 0 ? 1 : 0);
109
+ const otherCount = badProvenance.length - gitCount - supplyChainCount - notYetWiredCount;
110
+ const knownCategoryCount = (gitCount > 0 ? 1 : 0) + (supplyChainCount > 0 ? 1 : 0) + (notYetWiredCount > 0 ? 1 : 0);
102
111
 
103
112
  // Exactly one KNOWN category, and nothing outside it — the shape every
104
113
  // caller before this fix assumed was the only shape, and the one every
@@ -119,11 +128,17 @@ function _provenanceFailureReason(badProvenance, totalFindings) {
119
128
  `(a GitHub "Download ZIP" extracts without one). Run \`git init && git add -A && git commit -m init\` in ` +
120
129
  `the scanned directory, point the scan at a real \`git clone\`, or drop --assurance strict for standard/advisory.`;
121
130
  }
122
- return `${base} — ${supplyChainCount} of them describe an ABSENT dependency declaration ` +
123
- `(an unpinned version, a missing lockfile) that has no origin commit to resolve, by design. This is a ` +
124
- `known, permanent limitation: strict mode cannot pass while any are present, on any real project with ` +
125
- `such a dependency. Fix the underlying SCA finding(s) (pin the version / add a lockfile) if you want ` +
126
- `strict to pass, or use --assurance standard/advisory for a project you don't control the dependencies of.`;
131
+ if (supplyChainCount > 0) {
132
+ return `${base} ${supplyChainCount} of them describe an ABSENT dependency declaration ` +
133
+ `(an unpinned version, a missing lockfile) that has no origin commit to resolve, by design. This is a ` +
134
+ `known, permanent limitation: strict mode cannot pass while any are present, on any real project with ` +
135
+ `such a dependency. Fix the underlying SCA finding(s) (pin the version / add a lockfile) if you want ` +
136
+ `strict to pass, or use --assurance standard/advisory for a project you don't control the dependencies of.`;
137
+ }
138
+ return `${base} — ${notYetWiredCount} of them point at a real source location (a CDN script tag, a dynamic ` +
139
+ `require) this engine can't yet trace back to the commit that introduced it — unlike the ABSENT-declaration ` +
140
+ `case above, this is an ordinary coverage gap, not a permanent limitation, but it isn't fixable from your ` +
141
+ `side either. Use --assurance standard/advisory if you need this scan to pass today.`;
127
142
  }
128
143
 
129
144
  // Two or more independently-blocking categories on the SAME scan — the
@@ -133,28 +148,39 @@ function _provenanceFailureReason(badProvenance, totalFindings) {
133
148
  // rerun, and hit a second wall the first run already had full information
134
149
  // about but never mentioned — the same "the tool knew and didn't tell me"
135
150
  // complaint this whole function exists to fix, recurring in a milder form.
151
+ //
152
+ // Rendered as a bulleted, newline-separated list rather than one
153
+ // semicolon-joined paragraph (S2, adversarial premortem third pass,
154
+ // 2026-09-07) — each bullet is independently actionable, and a wall of
155
+ // clauses buried the fact that they are SEPARATE problems, each with its
156
+ // own fix, rather than one problem described three ways.
136
157
  const segments = [];
137
158
  if (gitCount > 0) {
138
159
  const gitReasonNames = gitReasons.map(([r]) => `"${r}"`).join(' and ');
139
- segments.push(`${gitCount} of them are ${gitReasonNames} (strict mode requires a real git repository ` +
140
- `run \`git init && git add -A && git commit\`, or scan a real \`git clone\`)`);
160
+ segments.push(`${gitCount} of them are ${gitReasonNames} strict mode requires a real git repository; ` +
161
+ `run \`git init && git add -A && git commit\`, or scan a real \`git clone\`.`);
141
162
  }
142
163
  if (supplyChainCount > 0) {
143
164
  segments.push(`${supplyChainCount} of them describe an ABSENT dependency declaration (unpinned version / ` +
144
165
  `missing lockfile) with no origin commit to resolve — a known, permanent limitation, not something a ` +
145
- `rerun will fix`);
166
+ `rerun will fix.`);
167
+ }
168
+ if (notYetWiredCount > 0) {
169
+ segments.push(`${notYetWiredCount} of them point at a real source location this engine can't yet trace ` +
170
+ `back to a commit — an ordinary coverage gap, not a permanent limitation, but not fixable from your side.`);
146
171
  }
147
172
  if (otherCount > 0) {
148
173
  if (otherReasons.length === 1) {
149
- segments.push(`${otherCount} share the reason "${otherReasons[0][0]}"`);
174
+ segments.push(`${otherCount} share the reason "${otherReasons[0][0]}".`);
150
175
  } else {
151
176
  const breakdown = otherReasons.slice(0, 5).map(([reason, n]) => `${n}× "${reason}"`).join(', ');
152
- segments.push(`${otherCount} break down as: ${breakdown}${otherReasons.length > 5 ? ', …' : ''}`);
177
+ segments.push(`${otherCount} break down as: ${breakdown}${otherReasons.length > 5 ? ', …' : ''}.`);
153
178
  }
154
179
  }
155
- return `${base} MULTIPLE distinct reasons, not just one: ${segments.join('; ')}. Every category above must ` +
156
- `be resolved for strict to pass (or drop to --assurance standard/advisory) fixing only one will surface ` +
157
- `the next on your following run.`;
180
+ const bullets = segments.map((s) => ` - ${s}`).join('\n');
181
+ return `${base} MULTIPLE distinct reasons, not just one:\n${bullets}\nEvery category above must be ` +
182
+ `resolved for strict to pass (or drop to --assurance standard/advisory) — fixing only one will surface the ` +
183
+ `next on your following run.`;
158
184
  }
159
185
 
160
186
  /**