@clear-capabilities/agentic-security-scanner 0.195.25 → 0.195.26

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.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,20 @@
9
9
  > make the history less accurate, not more.
10
10
 
11
11
 
12
+ ## 0.195.26 - GA programme, release F: composed router mounts, stale citations refused, frozen graph artifact contracts with a revision check
13
+
14
+ **Measured, 0.195.25:** `TIMINGS preflight=3s push=7s pr=5s checks=433s merge=6s verify=6s tag=2s release=223s npm=237s total=922s release-clock=237s`, shipped from the merge to the published release in 237 s; the npm listing lagged the publish and `ship --resume` confirmed it.
15
+
16
+ Three items of the GA plan's graph workstream that are code and tests: GA-03.2 (route-mount composition and hash-bound citations in context intelligence), GA-03.7 (frozen contracts for the graph artifacts, with wrong-revision refusal and partial-state propagation), and GA-03.6 (the incremental 3x target, measured and not met, with the reason recorded). Nothing moved a maturity.
17
+
18
+ - **Router mounts compose.** `router.get('/:id', h)` with `app.use('/api', auth, router)` is now the entry point `/api/:id`, not `/:id` with a `router-mount-not-resolved` reason. A mount is found in the same file, through the import map (`import users from './users.js'`, `const users = require('./users')`) or an inline `require('./users')`, when the target module exports its router receiver; mounts compose through intermediate routers (`/api` then `/users` then `/:id`), a router mounted at several prefixes is one entry point per prefix, and the mount statement's other identifier arguments are inherited middleware scoped to that mount and that mount only. A dynamic prefix mounts nothing and the route keeps its honest reason. The record keeps `registeredPath` beside the composed `pathTemplate` and carries the `mount` chain. Measured on `bench/dci-real-app` (committed outputs regenerated): the mounted-router case `GET /api/orders/:id` moved from unresolved to resolved, 26 resolved and 1 unresolved of 27 across the cases, precision and recall unchanged at 100%.
19
+ - **A stale citation is refused.** A review citation inside a context segment whose lines no longer hash to the segment's `spanHash` is declined as `stale-context`, beside the existing refusals for a citation outside the provided context or not grounded in its lines; a manifest validated against the current snapshot already reported `stale-span`, and now the review answers the same way.
20
+ - **Frozen artifact contracts** (`docs/reference/code-boundaries-contract.md`, `scanner/test/contracts/code-boundaries.contract.test.js`). The signed lineage graph, witness bundles, boundary contracts, context manifests, sink query keys and cut plans each have a field table the test holds in both directions, and each rule is exercised for real: a tampered or unsigned graph is refused by the one loader; a witness bundle verifies as `replayed` against its artifacts, `integrity-only` without them, and `invalid` when tampered, signed under another key or replayed against another graph; a boundary contract's digest covers its meaning and not its declarer; a context manifest with a changed span is stale and a forged one fails its hash; a sink query key changes with the graph and configuration digests; a cut plan is hypothetical and never verified. The `code-boundaries`, `graph-precision` and `context-intelligence` registry rows now name the contract page, the contract test, the limits section and a `since`, so `check-ga-contracts` runs the test on every release; the remaining GA-bar gaps on those Preview rows are a gate and hosted platform jobs.
21
+ - **The graph records its revision and a consumer can refuse another.** A scan inside a git repository writes `graph.scope.revision = { commit, worktreeDirty }` (and the graph id depends on the commit); `dataflow view --expect-revision <sha|HEAD>` refuses with `wrong-revision` a graph built from another commit, and also one that records no revision, since it cannot be shown to match. A build without a commit is byte-identical to before.
22
+ - **Incremental 3x end to end: measured, not met, reason recorded.** On the 300x8 synthetic workload the warm IR stage is about 165 ms against a 350 ms cold parse; the IR cache's load path is 79 ms of that (JSON parsing 41 ms is its floor; V8 deserialization of the same records measured slower, 99 ms) and the rest is the call graph build and resolution, rebuilt on every scan. With the deep stage already at 3x, end to end reaches 3x only if the warm IR stage drops to about 120 ms, which needs an incremental call graph rather than a cache tweak. The invalidation cases the plan lists (edit, rename, deletion, dependency, configuration, model) are already pinned against a cold scan; listed under open items on the DAG status page.
23
+
24
+ Gates, from the runs recorded for this entry: `test:lineage` 1590/1590 (two new files, `boundary-join`'s sibling `code-boundaries.contract.test.js` and `route-mounts.test.js` in their scopes), `test:discovery` 196/196, the dataflow command tests 19/19, full `npm test` 12660 pass, 1 fail, 35 skipped, where the one failure is `egress-transport.test.js`'s wall-budget case measuring 0 ms spent against a 1 ms budget under full-suite load and passing three of three runs alone (a timing flake in a file this release does not touch); `bench:mutation:check` 460/460; `bench:self-scan:check` no drift; `check-doc-drift --gate` exit 0; `bench:dci-real-app:check` current after regeneration.
25
+
12
26
  ## 0.195.25 - GA programme, release E: the lineage graph joins a queue publish to its receive and a store write to its read
13
27
 
14
28
  **Measured, 0.195.24:** `TIMINGS preflight=3s push=7s pr=4s checks=355s merge=6s verify=6s tag=2s release=162s npm=267s total=812s release-clock=176s`, shipped from the merge to the published release in 176 s; the npm listing lagged the publish and `ship --resume` confirmed it.
@@ -6745,6 +6745,15 @@ async function cmdFederateDeclare(args) {
6745
6745
  // hash-equivalent to a graph that never had the field at all,
6746
6746
  // regardless of how the hashing internals treat undefined values.
6747
6747
  const { crossRepoLinks: _omitForDigest, ...localGraphForDigest } = local.graph;
6748
+ // GA-03.7 (0.195.26): the graph also records the scanned revision
6749
+ // (`scope.revision`, with a dirty flag that flips on any untracked
6750
+ // file). The commit is already part of the graph id; the dirty flag is
6751
+ // not part of what the link names, so the revision record is left out of
6752
+ // this digest for the same reason crossRepoLinks is.
6753
+ if (localGraphForDigest.scope && localGraphForDigest.scope.revision) {
6754
+ const { revision: _omitRevision, ...scopeForDigest } = localGraphForDigest.scope;
6755
+ localGraphForDigest.scope = scopeForDigest;
6756
+ }
6748
6757
  const localGraphDigest = computeGraphDigest(localGraphForDigest);
6749
6758
  const idInputs = {
6750
6759
  localGraphId: local.graph.graphId, localGraphDigest, localNodeId: localNodeFlag,
@@ -98,7 +98,7 @@ async function loadProgram(root) {
98
98
  // ---------------------------------------------------------------------------------------------------------------------
99
99
 
100
100
  /**
101
- * agentic-security dataflow view [path] [--node <id> [--direction in|out|both] [--relations a,b] [--origins a,b]] [--output <file>]
101
+ * agentic-security dataflow view [path] [--node <id> [--direction in|out|both] [--relations a,b] [--origins a,b]] [--expect-revision <sha|HEAD>] [--output <file>]
102
102
  * Read-only over the signed lineage graph. Without --node it reports the view identity, counts, completion and the SCC
103
103
  * condensation of the data-flow relation. With --node it lists the neighbours the filter allows.
104
104
  */
@@ -114,7 +114,18 @@ async function cmdDataflowView(args) {
114
114
  if (f.node === undefined && (f.direction || f.relations || f.origins)) { err(`${who}: --direction, --relations and --origins apply to --node.`); return 2; }
115
115
 
116
116
  const { loadSignedGraph } = await __webpack_require__.e(/* import() */ 8218).then(__webpack_require__.bind(__webpack_require__, 78218));
117
- const loaded = loadSignedGraph(root);
117
+ // GA-03.7: `--expect-revision <sha|HEAD>` refuses a graph built from another revision (or from none).
118
+ let expectRevision = null;
119
+ if (f['expect-revision'] !== undefined) {
120
+ if (typeof f['expect-revision'] !== 'string' || !f['expect-revision']) { err(`${who}: --expect-revision needs a commit or HEAD.`); return 2; }
121
+ if (f['expect-revision'] === 'HEAD') {
122
+ const { getRepoState } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 83543));
123
+ const st = getRepoState(root);
124
+ if (!st || !st.head) { err(`${who}: --expect-revision HEAD needs a git repository at ${root}.`); return 2; }
125
+ expectRevision = st.head;
126
+ } else expectRevision = f['expect-revision'];
127
+ }
128
+ const loaded = loadSignedGraph(root, { expectRevision });
118
129
  if (!loaded.ok) { err(`${who}: ${loaded.message}`); return 1; }
119
130
  const { dataflowView, GraphViewError } = await __webpack_require__.e(/* import() */ 8158).then(__webpack_require__.bind(__webpack_require__, 88158));
120
131
  const { computeScc, verifyScc } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 41418));
@@ -126,6 +137,8 @@ async function cmdDataflowView(args) {
126
137
  schema: 'agentic-security/graph-view-report@1',
127
138
  maturity: 'preview',
128
139
  identity: view.identity,
140
+ revision: loaded.graph.scope && loaded.graph.scope.revision ? loaded.graph.scope.revision : null,
141
+ expectedRevision: expectRevision,
129
142
  metadata: view.metadata(),
130
143
  viewCompletion: view.completion(),
131
144
  note: 'A view is a read-only lens over the signed graph. An absent edge means the model has no such edge, not that the software has none.',
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clear-capabilities/agentic-security-scanner",
3
- "version": "0.195.25",
3
+ "version": "0.195.26",
4
4
  "description": "Scanner engine for the agentic-security Claude Code plugin: SAST, SCA with reachability and CISA KEV, secrets, IaC, Haskell and Nix/NixOS, prompt-injection, MCP/agent-tool audit, authZ analysis, SBOM, compliance attestation, and more.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -90,7 +90,7 @@
90
90
  "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-rust.test.js test/rust-taint-flow.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 test/sard-leakage-pipeline.test.js test/sard-split-scoring.test.js test/sard-llm-isolation.test.js test/sard-mutation-adversarial.test.js test/sard-baseline-adaptive-tolerance.test.js test/sard-independent-holdout.test.js test/sard-flow-aware-scoring.test.js test/sard-macro-score-support-floor.test.js test/sard-php-split.test.js test/parser-java-nary-concat.test.js test/sard-naive-baseline.test.js test/field-taint-cross-method.test.js test/field-taint-engine-unit.test.js test/coercion-sanitizer-kill.test.js test/constant-propagation-path-sensitivity.test.js test/parser-java-assignments.test.js test/catalog-java-sard.test.js test/parser-cs-juliet-shapes.test.js test/catalog-cs-sard-p2.test.js test/sard-cwe-key-merge.test.js test/parser-php-backtick.test.js test/parser-php-include.test.js test/php-include-merge.test.js test/parser-php-array-field-taint.test.js test/parser-php-cond-assign.test.js test/parser-rust-redos.test.js test/multi-sink-taint-chain.test.js test/static-field-cross-class-call-string.test.js test/regex-guard-narrowing.test.js test/object-instance-field-taint.test.js test/param-type-inference.test.js test/smt-path-feasibility.test.js test/cross-service-taint.test.js test/dataflow-expr-taint-scaling.test.js test/evaluation/guard-dominance.test.js test/evaluation/engine-mechanisms.test.js test/rx-exec-receiver.test.js test/incremental-dependency.test.js test/incremental-integrity.test.js test/demand-query.test.js test/ir-cache.test.js test/canonicalize-parity.test.js test/dataflow-source-attribution.test.js",
91
91
  "test:mcp": "node --test test/mcp.test.js test/mcp-apply-fix-multifile.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 test/capabilities/tools.test.js",
92
92
  "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/git-history-batch.test.js test/default-scan-drift.test.js test/bundle-optional-deps.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",
93
- "test:lineage": "node --test test/lineage/analysis-completion.test.js 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/seeding-across-calls.test.js test/lineage/boundary-join.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 test/lineage/runtime-assurance.test.js test/lineage/runtime-edge-states.test.js test/lineage/runtime-explorer-view.test.js test/cli/runtime-explorer-cli.test.js test/cli/runtime-identity-cli.test.js test/cli/runtime-twin-cli.test.js test/lineage/cut-planner.test.js test/lineage/scc.test.js test/lineage/scc-solver.test.js test/graph/graph-views.test.js test/lineage/dag07-completion.test.js test/lineage/owned-build.test.js test/dataflow/boundary-propagation.test.js test/lineage/boundary-contract.test.js test/lineage/correlation-v2.test.js test/lineage/path-control-evidence.test.js test/lineage/smt-z3-backend.test.js test/cli/dag-commands.test.js",
93
+ "test:lineage": "node --test test/lineage/analysis-completion.test.js 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/seeding-across-calls.test.js test/lineage/boundary-join.test.js test/contracts/code-boundaries.contract.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 test/lineage/runtime-assurance.test.js test/lineage/runtime-edge-states.test.js test/lineage/runtime-explorer-view.test.js test/cli/runtime-explorer-cli.test.js test/cli/runtime-identity-cli.test.js test/cli/runtime-twin-cli.test.js test/lineage/cut-planner.test.js test/lineage/scc.test.js test/lineage/scc-solver.test.js test/graph/graph-views.test.js test/lineage/dag07-completion.test.js test/lineage/owned-build.test.js test/dataflow/boundary-propagation.test.js test/lineage/boundary-contract.test.js test/lineage/correlation-v2.test.js test/lineage/path-control-evidence.test.js test/lineage/smt-z3-backend.test.js test/cli/dag-commands.test.js",
94
94
  "test:bench-modules": "node --test test/phase4-harness.test.js test/pipeline.test.js test/proof-corpus-lib.test.js test/proof-corpus-runner.test.js",
95
95
  "test:server": "node --test test/server/graph-loader.test.js test/server/security.test.js test/server/routes.test.js test/server/http-server.test.js test/server/cmd-explore.test.js test/server/cmd-dataflow-export.test.js test/server/static-assets.test.js test/server/dataflow-scenario-cli.test.js test/server/dataflow-impact-cli.test.js",
96
96
  "test:haskell": "node --test test/haskell/haskell-reachability.test.js test/haskell/haskell-real-code-shapes.test.js test/haskell/haskell-unseen-v5-shapes.test.js test/haskell/haskell-unseen-v4-shapes.test.js test/haskell/haskell-alias-taint.test.js test/haskell/haskell-weak-hash-names.test.js test/haskell/haskell-models-extended.test.js test/haskell/haskell-rules-extended.test.js test/haskell/haskell-injection.test.js test/haskell/haskell-ir.test.js test/haskell/haskell-manifests.test.js test/haskell/haskell-parser.test.js test/haskell/haskell-remediation.test.js test/haskell/haskell-remediation-0190.test.js test/haskell/haskell-remediation-kdf.test.js test/haskell/haskell-remediation-html-text.test.js test/haskell/haskell-remediation-scotty-body.test.js test/haskell/haskell-remediation-entropy.test.js test/haskell/haskell-remediation-text-command.test.js test/haskell/haskell-remediation-path-contain.test.js test/haskell/haskell-remediation-0195-16.test.js test/haskell/haskell-taint-shapes.test.js test/haskell/haskell-real-advisory-shapes.test.js test/haskell/haskell-discovery-shapes.test.js test/haskell/haskell-quasiquote-interp.test.js test/haskell/haskell-record-dot.test.js test/haskell/haskell-global-cell.test.js test/haskell/haskell-syntax-extensions.test.js test/haskell/haskell-rule-precision.test.js test/haskell/haskell-resolved-graph.test.js test/haskell/haskell-sca.test.js test/haskell/haskell-sca-severity.test.js test/haskell/haskell-web-guards.test.js test/haskell/haskell-advisory-feed.test.js test/haskell/haskell-security-rules.test.js test/haskell/haskell-taint.test.js test/haskell/haskell-boundaries.test.js test/haskell/haskell-live-feed-scan.test.js test/haskell/haskell-supply-bounds.test.js test/haskell/haskell-ir-scaling.test.js test/haskell/haskell-boundary-propagation.test.js test/haskell/haskell-generalization.test.js test/haskell/haskell-trust-boundary.test.js test/haskell/haskell-trust-fixed-file.test.js test/haskell/haskell-predictable-random-flow.test.js test/haskell/haskell-comment-invariance.test.js test/haskell/haskell-remediation-classes.test.js test/haskell/haskell-trust-boundary-frameworks.test.js test/haskell/haskell-generic-detectors.test.js",
@@ -133,7 +133,7 @@
133
133
  "verification:replay-example": "node ../scripts/verification-replay-example.mjs",
134
134
  "test:lifecycle": "node --test test/ci-hang-protection.test.js test/gate-select.test.js test/ci-test-shards.test.js test/pre-bash-guard.test.js test/lsp-protocol-smoke.test.js test/ide-surfaces.test.js test/detector-liveness.test.js test/bench-watchdog.test.js test/ci-parity.test.js test/dead-code.test.js test/no-dead-modules.test.js test/no-orphan-scripts.test.js test/no-stray-state.test.js test/tree-integrity.test.js test/stop-hook.test.js test/plugin-self-check.test.js test/skills-registry.test.js test/bodyguard.test.js test/cache-invalidator-guard.test.js test/dispatch-pre-tool.test.js test/dispatch-user-prompt.test.js test/session-start-model-capture.test.js test/sandbox.test.js test/sandbox-escape.test.js test/trust-boundary.test.js test/ci-templates.test.js test/agent-mcp-tools.test.js test/triage-command.test.js test/no-orphan-tests.test.js test/supply-command.test.js test/posture-command.test.js test/labs-command.test.js test/compliance-command.test.js test/check-doc-drift.test.js test/gate-warm.test.js test/docs-positioning.test.js test/dist-chunks-tracked.test.js test/ga-program.test.js test/workflow-confinement.test.js test/check-bundle-source.test.js test/ship.test.js test/release-prepare.test.js && node ../scripts/lint-command-descriptions.mjs",
135
135
  "test:eval": "node --test test/independent-eval.test.js test/realworld-recall.test.js",
136
- "test:discovery": "node --test test/discovery-spec-synthesis.test.js test/discovery-partition.test.js test/discovery-lenses.test.js test/discovery-hunter.test.js test/discovery-confirm.test.js test/discovery-disprove.test.js test/discovery-judge.test.js test/discovery-run.test.js test/discovery-wiring.test.js test/discovery-llm-invoke.test.js test/local-only-mode.test.js test/context-intelligence/build-js.test.js test/context-intelligence/build-python-haskell.test.js test/context-intelligence/hie-adapter.test.js test/context-intelligence/store.test.js test/context-intelligence/review-queue.test.js test/context-intelligence/packer-egress.test.js test/context-intelligence/evaluation.test.js test/context-intelligence/queue-diff.test.js test/context-intelligence/cli.test.js test/context-intelligence/resilience.test.js test/context-intelligence/frameworks.test.js test/context-intelligence/skew-git-rls.test.js test/context-intelligence/premortem.test.js test/context-intelligence/git-diff-candidates.test.js",
136
+ "test:discovery": "node --test test/discovery-spec-synthesis.test.js test/discovery-partition.test.js test/discovery-lenses.test.js test/discovery-hunter.test.js test/discovery-confirm.test.js test/discovery-disprove.test.js test/discovery-judge.test.js test/discovery-run.test.js test/discovery-wiring.test.js test/discovery-llm-invoke.test.js test/local-only-mode.test.js test/context-intelligence/build-js.test.js test/context-intelligence/build-python-haskell.test.js test/context-intelligence/hie-adapter.test.js test/context-intelligence/store.test.js test/context-intelligence/review-queue.test.js test/context-intelligence/route-mounts.test.js test/context-intelligence/packer-egress.test.js test/context-intelligence/evaluation.test.js test/context-intelligence/queue-diff.test.js test/context-intelligence/cli.test.js test/context-intelligence/resilience.test.js test/context-intelligence/frameworks.test.js test/context-intelligence/skew-git-rls.test.js test/context-intelligence/premortem.test.js test/context-intelligence/git-diff-candidates.test.js",
137
137
  "eval:independent": "node ../bench/independent-eval/runner.mjs",
138
138
  "eval:independent:gate": "node ../bench/independent-eval/runner.mjs --gate default",
139
139
  "smoke": "node bin/agentic-security.js scan test/fixtures/vulnerable-js",
@@ -33,7 +33,7 @@ export const modules = {
33
33
 
34
34
  /**
35
35
  * @param {string} scanRoot
36
- * @returns {{ok:true, graph:object} | {ok:false, reason:'missing'|'unsigned'|'tampered'|'malformed', message:string}}
36
+ * @returns {{ok:true, graph:object} | {ok:false, reason:'missing'|'unsigned'|'tampered'|'malformed'|'wrong-revision', message:string}}
37
37
  *
38
38
  * Four, and only four, distinct failure reasons — each with its own clear
39
39
  * message so an operator knows exactly what to do next:
@@ -50,7 +50,7 @@ export const modules = {
50
50
  * valid JSON. Should not happen from a normal scan; the
51
51
  * file may be corrupted on disk after signing.
52
52
  */
53
- function loadSignedGraph(scanRoot) {
53
+ function loadSignedGraph(scanRoot, { expectRevision = null } = {}) {
54
54
  const graphPath = (0,_posture_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.statePath)(scanRoot, 'lineage-graph.json');
55
55
  const sigPath = graphPath + '.sig';
56
56
 
@@ -100,6 +100,23 @@ function loadSignedGraph(scanRoot) {
100
100
  };
101
101
  }
102
102
 
103
+ // GA-03.7 (0.195.26): wrong-revision refusal. A caller that knows which
104
+ // revision it expects (`dataflow view --expect-revision`) gets a graph
105
+ // only when the graph records that revision; a graph that records none
106
+ // cannot prove it and is refused for the same reason, never served on
107
+ // the hope that it matches.
108
+ if (expectRevision) {
109
+ const have = graph && graph.scope && graph.scope.revision ? graph.scope.revision.commit : null;
110
+ if (have !== expectRevision) {
111
+ return {
112
+ ok: false,
113
+ reason: 'wrong-revision',
114
+ message: have
115
+ ? `Lineage graph at ${graphPath} was built from revision ${have}, not the expected ${expectRevision}. Re-run the scan on the expected revision.`
116
+ : `Lineage graph at ${graphPath} records no revision, so it cannot be shown to match the expected ${expectRevision}. Re-run the scan inside the repository (AGENTIC_SECURITY_LINEAGE_DEEP=1) so the graph records its revision.`,
117
+ };
118
+ }
119
+ }
103
120
  return { ok: true, graph };
104
121
  }
105
122