@clear-capabilities/agentic-security-scanner 0.161.0 → 0.162.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.
- package/CHANGELOG.md +20 -0
- package/bin/agentic-security.js +11 -2
- package/dist/4113.index.js +59 -8
- package/dist/5613.index.js +500 -0
- package/dist/6239.index.js +469 -0
- package/dist/7838.index.js +38 -2
- package/dist/8798.index.js +1 -1
- package/dist/9207.index.js +5 -0
- package/dist/9560.index.js +36 -22
- package/dist/{1905.index.js → 9999.index.js} +265 -8
- package/dist/agentic-security.mjs +2 -2
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +9 -4
- package/src/discovery/CLAUDE.md +9 -0
- package/src/discovery/index.js +28 -0
- package/src/discovery/memory.js +7 -5
- package/src/fix/apply-fix-service.js +33 -3
- package/src/mcp/CLAUDE.md +9 -1
- package/src/mcp/tools.js +17 -4
- package/src/posture/CLAUDE.md +174 -0
- package/src/posture/assurance/baseline-inventory.js +218 -0
- package/src/posture/assurance/baseline.js +322 -0
- package/src/posture/assurance/bounded-io.js +145 -0
- package/src/posture/assurance/config.js +299 -0
- package/src/posture/assurance/contracts.js +315 -0
- package/src/posture/assurance/identity.js +62 -0
- package/src/posture/assurance/migrations.js +259 -0
- package/src/posture/assurance/schema-kit.js +111 -0
- package/src/posture/assurance/verification-record.js +258 -0
- package/src/posture/attestation.js +5 -0
- package/src/posture/autopilot.js +28 -1
- package/src/posture/evidence-bundle.js +93 -7
- package/src/posture/execution-proof.js +11 -1
- package/src/posture/fix-verify-loop.js +20 -6
- package/src/posture/fix-verify.js +37 -2
- package/src/posture/oracles/adapters.js +360 -0
- package/src/posture/oracles/conformance.js +275 -0
- package/src/posture/oracles/oracle.js +433 -0
- package/src/posture/oracles/registry.js +76 -0
- package/src/posture/oracles/scenario-classes.js +223 -0
- package/src/posture/replay/replay.js +249 -0
- package/src/posture/verification/advisory-state.js +71 -0
- package/src/posture/verification/emit.js +257 -0
- package/src/posture/verification/hypothesis-promotion.js +211 -0
- package/src/posture/verification/patch-negative.js +214 -0
- package/src/posture/verification/patch-promotion.js +105 -0
- package/src/posture/verification/projection.js +183 -0
- package/src/posture/verification/repair-records.js +124 -0
- package/src/posture/verifier.js +16 -0
- package/src/report/index.js +49 -0
- package/src/sandbox/CLAUDE.md +41 -0
- package/src/sandbox/backend-namespace.js +7 -0
- package/src/sandbox/backend-userspace.js +68 -29
- package/src/sandbox/control-probes.js +215 -0
- package/src/sandbox/supervise.js +201 -0
- package/src/sandbox/trust-boundary.js +113 -0
- package/src/sandbox/trust-domains.js +171 -0
package/src/posture/CLAUDE.md
CHANGED
|
@@ -96,6 +96,8 @@ Wired in `bin/agentic-security.js` after every filter and after `makeDeterminist
|
|
|
96
96
|
|
|
97
97
|
**`verifyRunAttestation` now has two real callers.** `agentic-security verify-attestation <file>` auto-detects whether the given JSON is an evidence bundle (`.finding`+`.signature`, verified via `evidence-bundle.js`'s Ed25519 path, unchanged) or a run attestation (`.digest`+`.canonicalisation`, either bare or embedded under a full `last-scan.json`'s `.attestation` field) and dispatches accordingly. A run attestation isn't self-contained the way a bundle is — verifying it means re-scanning the project (`--against <path>`, default `.`) and confirming the fresh scan reproduces the attested digest, which is the actual, meaningful claim this artifact makes ("does this codebase, scanned now, match what was attested earlier"). Separately, `scripts/release-check.mjs`'s `attestation-self-check` gate round-trips a synthetic finding set through compute→verify (and a mutated copy through verify, which must fail) on every release, catching a broken canonicalisation or signing path before it ships — independent of whether any project ever calls `verify-attestation` on a real artifact.
|
|
98
98
|
|
|
99
|
+
**Issuer and trust basis (CORE-003.AC03).** `evidence-bundle.js` signs an `issuance` block inside the canonical bytes (only when present, so pre-existing bundles keep their signatures): issuer id and key fingerprint, `trustBasis: 'self-issued-local-key'`, `independentlyCertified: false`, and a plain statement. `verifyEvidenceBundle` returns `trustBasis`/`issuer`/`trustNote`; a bundle with no `issuance` verifies and is reported `none-declared` (never as trusted); an unknown basis, an `independentlyCertified: true` claim, or an issuer fingerprint that is not the verifying key is rejected even when validly signed. The only basis this build can verify is the local one: a third-party basis needs a trust-root policy that does not exist here. A signed run attestation carries the same self-issued label. `verify-attestation` exit codes are unchanged. Signing keys are protected from workers by `sandbox/trust-boundary.js` (see `sandbox/CLAUDE.md`). Suite: `test/evidence-issuer.test.js`.
|
|
100
|
+
|
|
99
101
|
**Integrity + signing** — `integrity.js` (per-install HMAC for `last-scan.json`), `rule-pack-signing.js`. The HMAC key lives at `$XDG_CONFIG_HOME/agentic-security/scan-key`; override via `$AGENTIC_SECURITY_HMAC_KEY`. Premortem-derived; do not regress to hostname-derived.
|
|
100
102
|
|
|
101
103
|
**Rule lifecycle** — `custom-rules.js` (YAML pattern DSL), `rule-overrides.js` (`disable:` gated on signature), `rule-packs.js`, `rule-synthesis.js` (proposes suppressions from triage feedback), `ruleset-version.js`.
|
|
@@ -139,6 +141,178 @@ one was caught by the module's own test, not in review.
|
|
|
139
141
|
- **No throwing.** Every annotation in `engine.js` is wrapped `try { … } catch (_) {}`. Your annotator must degrade gracefully — set `null` on the field and continue.
|
|
140
142
|
- **Dead-module test.** `npm run test:lifecycle` fails the build if you export a public symbol from a posture module that no other source file imports. Wire it in `engine.js` (or allowlist it with a written reason in `test/no-dead-modules.test.js`).
|
|
141
143
|
|
|
144
|
+
## Assurance contracts, baseline and rollout config — `assurance/` (9 modules)
|
|
145
|
+
|
|
146
|
+
Foundation for the differentiation work (CORE-001, CORE-002, CORE-004). All of it is pure or read-only, and **nothing in it is wired into `engine.js` or the scan/report path**: a default scan is byte-for-byte unaffected, which `test/posture/assurance-config.test.js` pins. Consumers (X-201 and later) import it directly.
|
|
147
|
+
|
|
148
|
+
- **`identity.js`**: ids for evidence records. Reuses `canonicalJson` (`evidence-bundle.js`) and `computeStableId` (`stable-id.js`, a hypothesis id is a finding's stable id). An id is a hash over an **allowlist** of semantic fields, so clocks (`createdAt`) and migration bookkeeping can never reach it. Prefixes `vrec/obind/capd/rlab/rev` are distinct from lineage's, and nothing here imports `lineage/` (a test checks that).
|
|
149
|
+
- **`schema-kit.js`**: validator primitives. Closed-world (unknown fields rejected), typed error codes, supported major version 1 only, `sha256:<64 hex>` digests.
|
|
150
|
+
- **`verification-record.js`**: the one verification record. Six distinct outcomes, a SEPARATE repair status, four evidence kinds. Structural rules: a model can only produce `inference`; `confirmed` needs referenced trusted-runtime-proof or independent-adjudication evidence; `confirmationLevel` must equal the level derived from the evidence (a forged level fails); `refuted` needs an applicable non-model oracle, valid preconditions and proving evidence.
|
|
151
|
+
- **`contracts.js`**: observation binding (references a lineage observation by id only; absence in a sampled observation cannot establish `blocked`), capability decision (only runner/proxy mediation with a backend and an active-probe digest may claim `enforced`; a hook or in-process check never can), routing label (a decided label must name an adjudication or trusted-execution source), release evidence (`complete` is derived, never trusted), and `validateRecordSet` for duplicate ids, dangling references and conflicting claims.
|
|
152
|
+
- **`migrations.js`**: explicit v1 adapters from legacy shapes (proof tier, boolean verified, egress decision, attestation, lineage observation) and a legacy view back out. Evidence can be lost, never invented: a legacy `true` is `inconclusive`, `proof-failed` is `inconclusive` not `refuted`, and the only route to `confirmed` is an explicit `trustedRunner` assertion bound to a commit. The legacy view's `verified` is `true` only for confirmed and `false` only for refuted, otherwise `null`.
|
|
153
|
+
- **`config.js`**: the unified feature configuration. Reuses the env/`.agentic-security/*.yml` mechanism. Precedence: kill switch (`AGENTIC_SECURITY_NO_ASSURANCE` or `AGENTIC_SECURITY_NO_<FEATURE>`) > explicit override > `AGENTIC_SECURITY_ASSURANCE_<FEATURE>` > `.agentic-security/assurance.yml` > default (everything off). **A project file can never enable a `high-risk-execution` feature** (the file lives in the scanned repo); invalid configuration fails closed; unsupported platforms return a typed `unsupported` with the disclosure. `runFeature` returns typed `blocked`/`unsupported`/`degraded`/`disabled` results and never prompts.
|
|
154
|
+
- **`bounded-io.js`**: `guardedModelCall` is the only route for new model/network calls. It owns no HTTP client (the transport is injected): feature gate, then `evaluateEgress` BEFORE the payload exists, then `redactPayload`, then the request-size limit, then deadline plus bounded retries, then output cap, with every decision appended to the existing egress audit chain. `readFileBounded`, `capOutput`, `withDeadline`, `retryBounded` enforce the limits `config.js` claims; `maxMemoryMiB` is carried for a runner and disclosed as not enforced here.
|
|
155
|
+
- **`baseline.js`, `baseline-inventory.js`**: baseline capture (`scripts/baseline-capture.mjs`, `npm run baseline:capture`). Read-only; records HEAD, dirty paths, exact source and bundle digests, tool versions, entry points, the seven mappings and an 18-entry capability inventory (implemented / partial / unsupported / unmeasured, every path and exported symbol verified at capture time, a missing one is a reported problem). Unknown facts are `{status:'unknown', reason}` with no value. `evaluateBaseline` invalidates exactly the capabilities whose cited files changed and lists unrelated user changes as retained/introduced. The manifest is machine-specific, so it is generated on demand and not committed. When you change a capability's source or tests, update its inventory entry in the same change.
|
|
156
|
+
|
|
157
|
+
Tests: `test/posture/assurance-{baseline,contracts,config}.test.js`, all in `test:posture`.
|
|
158
|
+
|
|
159
|
+
## One verification record, trusted oracles and replay (X-201, X-202, X-203)
|
|
160
|
+
|
|
161
|
+
Built on `assurance/` (the record schema, migrations, config) and `sandbox/trust-boundary.js` (the boundary). Three
|
|
162
|
+
directories, all consumed rather than wired into the default scan: a default scan is unchanged, and every addition to an
|
|
163
|
+
existing output is an additive field.
|
|
164
|
+
|
|
165
|
+
**`verification/emit.js`: the one emit function (X-201).** `emitVerification(surface, source, ctx)` is what every
|
|
166
|
+
verification surface calls to get the version-1 record (`{ ok, record, legacy, errors }`, never throws, validated before it
|
|
167
|
+
returns). Surfaces and where they call it: `fix-verify.js` (`verificationRecord` on the result, which the MCP `verify_fix` and
|
|
168
|
+
`apply_fix` tools forward), `fix-verify-loop.js`, `execution-proof.js` (`proveFinding` result), `verifier.js`
|
|
169
|
+
(`verifierVerificationRecords`, called by the CLI `verify` command into its `verifier-runs/` run record, never onto the findings that
|
|
170
|
+
are written back to `last-scan.json`), `autopilot.js` (`rec.verificationRecord`, `commit` option), `discovery/index.js` (hunt:
|
|
171
|
+
`verificationRecords`, advisory) and `oracles/oracle.js` (the `oracle` surface). The rule for every mapping: evidence is lost,
|
|
172
|
+
never invented, so no legacy surface can reach `confirmed` or `refuted`. A PoC run under the older sandbox path is `inconclusive`
|
|
173
|
+
(not a trusted runner; `proof-failed` is a triage signal, not a refutation), a static re-scan with no exploit oracle is `not-run`,
|
|
174
|
+
a family with no oracle is `unsupported`, a harness failure is `error`, a model verdict is `inference` evidence only. Only
|
|
175
|
+
`oracle` emissions carry trusted-runner evidence, because only `oracles/oracle.js` builds them.
|
|
176
|
+
|
|
177
|
+
Legacy consumers: nothing existing was renamed or removed. For a consumer that wants a status or a boolean, `toLegacyVerificationView`
|
|
178
|
+
(`assurance/migrations.js`, also returned as `legacy`) maps `verified` to `true` only for `confirmed` and `false` only for `refuted`,
|
|
179
|
+
`null` for the other four, and carries `status` with the real outcome name, so a skipped check can never read as a pass and an unrun
|
|
180
|
+
check never as a failure. Native vocabularies keep their own fields (`proofTier`, `verifier_verdict`, autopilot `outcome`, fix-verify
|
|
181
|
+
`ok`); the record sits beside them as `verificationRecord`. A boolean `true` migrated from a legacy record is `inconclusive`.
|
|
182
|
+
|
|
183
|
+
**`oracles/` (X-202).** `oracle.js` is the adapter contract (`validateOracleSpec`, `defineOracle`) and the runner (`runOracle`).
|
|
184
|
+
`adapters.js` holds the five class adapters (injection-execution, authorization-decision, state-transition,
|
|
185
|
+
side-effect-reachability, parser-resource), `registry.js` the frozen registry and `oracleManifest()`, the machine-readable
|
|
186
|
+
description X-208 gates on (class, prerequisites, platforms with an honest per-platform status, budgets, negative controls,
|
|
187
|
+
fixture locations, limitations, logic digest). Fixtures: `test/fixtures/oracles/<class>/{positive,negative,inconclusive}`.
|
|
188
|
+
- A run is: feature gate (`verification-oracles`, off by default, operator-only), request validation (closed-world: labels,
|
|
189
|
+
verdicts and receipts are never accepted; reserved `__oracle_*` names and path escapes are refused), prerequisite check
|
|
190
|
+
(an unmet one is `unsupported` with a typed reason and the target is never executed), a fresh workspace plus a verifier-owned
|
|
191
|
+
evidence directory outside it, the target through `runInBoundary` ONLY (a test pins that `oracle.js` imports no other way to
|
|
192
|
+
run code), a digest check of the adapter's own harness (a target that rewrote it makes the run `error`), then verifier-side
|
|
193
|
+
interpretation of what the run left behind, read after the whole process tree is dead. The settled status comes from
|
|
194
|
+
`settleVerification` with `observedBy: 'verifier'` evidence; a decided result (`confirmed`/`refuted`) additionally needs an
|
|
195
|
+
exact commit, else it is held at `inconclusive`.
|
|
196
|
+
- `refuted` needs the adapter's own precondition (a benign control passed); a target that failed to load, exited early or never
|
|
197
|
+
reported is `inconclusive`. A run cut by its deadline decides nothing except for the parser/resource class, where the supervisor's
|
|
198
|
+
own deadline observation IS the measurement.
|
|
199
|
+
- Receipts are issued only by `runOracle` (a WeakSet records them; they are deep-frozen; a copy or hand-built one is not
|
|
200
|
+
`isIssuedReceipt`). They carry the observed output (capped), the logic digest, sanitized environment metadata (an allowlist: no
|
|
201
|
+
hostname, paths or environment values) and the record id. Unsigned: signing belongs to the signer domain.
|
|
202
|
+
- Platforms: macOS (userspace backend) is the only host these have been executed on. Linux is declared `unverified` in the
|
|
203
|
+
manifest and cannot be `supported`; today the boundary refuses to run on the namespace backend, which the runner reports as
|
|
204
|
+
`unsupported`. Changing what an adapter asserts means bumping its `version` (the harness text and version feed `logicDigest`).
|
|
205
|
+
- KNOWN LIMIT: the target is imported into the harness process. A target written to recognise the oracle's payload and forge the
|
|
206
|
+
effect artifact is not distinguishable from a real injection; the oracle bounds the effect it tests, it is not a defence
|
|
207
|
+
against a target built to fool it. Tamper controls cover what a worker or target can do to adapter logic, labels, receipts and
|
|
208
|
+
status text.
|
|
209
|
+
|
|
210
|
+
**`replay/replay.js` (X-203).** A replay manifest pins the repository commit, the patch hash, the fixture hash, the toolchain
|
|
211
|
+
(runtime version, platform, architecture, and a container digest when there is one), the oracle id, version and logic digest, the
|
|
212
|
+
inputs and the budgets. It is a description of an oracle run, not a second runner: `replayManifest` ends in `runOracle`, so the
|
|
213
|
+
supervised process tree, output cap and cleanup are the existing ones. It rejects, and nothing executes, on a content hash that does
|
|
214
|
+
not match, an oracle that changed since the manifest was made, a scope wider than "exactly the named oracle, no network,
|
|
215
|
+
workspace-only writes", a budget over the oracle's ceiling, an unsafe file path or an unknown field. Missing toolchain, container
|
|
216
|
+
runtime or image, a denied network (acquisition is never attempted: this build fetches nothing), a disabled feature or a boundary
|
|
217
|
+
that cannot run are typed prerequisites with `resumable` set honestly; the attempt is parked (`awaiting-prerequisites`) and
|
|
218
|
+
`resume` re-evaluates the prerequisites against the real host (a claim that they are met does nothing). Outcome while parked is
|
|
219
|
+
`not-run` (or `unsupported` when this build can never meet it, such as container execution, which is not implemented), with no
|
|
220
|
+
evidence; nothing is substituted for the execution that did not happen. Toolchain identity is exact. Persistence of attempts is
|
|
221
|
+
the caller's (the attempt object is plain data). Suites: `test/verification/{verification-record,oracle-adapters,replay-manifest}.test.js`
|
|
222
|
+
(`npm run test:verification`).
|
|
223
|
+
|
|
224
|
+
## Patch-negative verification and non-taint classes (X-204, X-205)
|
|
225
|
+
|
|
226
|
+
Same posture as the three directories above: consumed, not wired into the default scan, every output addition additive, and
|
|
227
|
+
nothing changes with the feature flags off. Suites: `test/verification/{patch-negative,non-taint-classes}.test.js`
|
|
228
|
+
(`npm run test:verification`).
|
|
229
|
+
|
|
230
|
+
**`verification/patch-negative.js` (X-204).** `verifyPatchNegative(req, { config, runOptions })` is `verified-fix` only when four
|
|
231
|
+
`replayManifest` runs (so each is pinned, boundary-confined and receipted) show: the exploit oracle CONFIRMS on the original
|
|
232
|
+
revision, REFUTES on original-plus-diff, and the `functional-regression` oracle (the requester's declared cases) is clean on the
|
|
233
|
+
original (a baseline: wrong expectations are reported, not blamed on the patch) and on the patched revision. It stops at the first
|
|
234
|
+
non-passing step and names it: the result carries `incompleteStep` and a typed `failureCode` (`original-not-reproduced`,
|
|
235
|
+
`patched-still-exploitable`, `patched-build-broken`, `functional-omitted`, `functional-baseline-invalid`,
|
|
236
|
+
`functional-regression-detected`, `oracle-changed`, `revision-unbound`, `prerequisite-unmet` (resumable where stated),
|
|
237
|
+
`environment-mismatch`, `promotion-refused`) and a `summary` that says what was and was not exercised. Gate: the
|
|
238
|
+
`patch-negative-verification` feature (high-risk execution, operator-only, off by default) plus `verification-oracles`.
|
|
239
|
+
Wiring: `fix-verify.js` (`verifyFix({ patchNegative, assuranceConfig })` adds `patchNegative` and `fixStatus`, and `ok` requires
|
|
240
|
+
`verified-fix`), `fix-verify-loop.js` (a `patchNegative` leg and the `verified-fix` verdict) and `fix/apply-fix-service.js`
|
|
241
|
+
(`applyVerifiedFix({ patchNegative })` writes only a promoted patch and returns `repairRecords`). With the flag off or no request,
|
|
242
|
+
those return exactly what they did before.
|
|
243
|
+
|
|
244
|
+
**`verification/patch-promotion.js`.** `promotePatch({ proposal, receipts })` re-derives the diff digest and revision from the
|
|
245
|
+
PROPOSAL and refuses any receipt that was not issued by `runOracle` (`isIssuedReceipt`: copies and hand-built receipts fail), that
|
|
246
|
+
covers different content than the exact diff on the original revision, that was issued for another commit or hypothesis, whose
|
|
247
|
+
oracle or inputs differ between the original and patched runs, whose environment identity differs, or that is reused in two roles.
|
|
248
|
+
Receipts are valid inside the verifier's process only; carrying a promotion across processes needs a signing domain (not here).
|
|
249
|
+
|
|
250
|
+
**`verification/repair-records.js`.** The CORE-002 record has one repair status and no value for a rejection, so the history is an
|
|
251
|
+
append-only ledger of separate, frozen, chained records: `proposed`, `rejected`, `promoted` (only through `recordPromotion`, which
|
|
252
|
+
accepts nothing but a result `promotePatch` returned `ok`), `applied` (only after a promotion for that exact diff) and
|
|
253
|
+
`rolled-back`. `verificationRepairFor`/`withRepairStatus` map the ledger onto the CORE-002 `repair` field (`replay-verified` carries the
|
|
254
|
+
patched-negative record id); a rejection leaves it at `proposed` because the foundation enum is not widened here. The ledger is
|
|
255
|
+
returned to the caller and not persisted: persisting it would need an artifact-registry classification.
|
|
256
|
+
|
|
257
|
+
**New adapters.** `replay-idempotency` (a factory receiving a recording stand-in for the effect: a request and a distinct request
|
|
258
|
+
are delivered as a control, then the same request is redelivered, and the verifier counts effects) and `functional-regression`
|
|
259
|
+
(declared cases against expected JSON values; the hypothesis is that behaviour REGRESSED, so a clean patch is `refuted`). Both have
|
|
260
|
+
the usual positive, negative and inconclusive fixtures under `test/fixtures/oracles/`.
|
|
261
|
+
|
|
262
|
+
**`oracles/scenario-classes.js` (X-205).** The supported-class manifest for non-taint defects, surfaced as
|
|
263
|
+
`oracleManifest().nonTaint`: tenant authorization and privileged action (REUSE `authorization-decision`), workflow order (REUSES
|
|
264
|
+
`state-transition`), bounded resource exhaustion (REUSES `parser-resource`) and replay/idempotency (the new adapter). Each class
|
|
265
|
+
lists what the requester must supply, its fixtures (`test/fixtures/non-taint/<class>/{positive,negative,scenario.json}`, application-style
|
|
266
|
+
code), its limitations and the report lines a reader sees; every `runOracle` result additionally carries a `disclosure`
|
|
267
|
+
(prerequisites, platform statement, limitations, class report). Unsupported non-taint classes (concurrent races, CSRF, authentication
|
|
268
|
+
throttling) are named with a reason. `judgeNonTaintHypothesis` is the rule that taint absence is never an input to a refutation:
|
|
269
|
+
without an executed oracle of the class's own adapter with proven preconditions the outcome is `not-run` (or `unsupported`); the hunt
|
|
270
|
+
mapper in `verification/emit.js` uses it. `trustedNegativeDenominator` counts only decided results of an executed oracle of an
|
|
271
|
+
advertised class with proven preconditions and trusted runtime proof, and lists every exclusion with its reason (its runtime consumer is `verificationCoverage` in
|
|
272
|
+
`verification/projection.js`, which the JSON report, the CLI report and the MCP/autopilot surfaces use for the trusted-negative line).
|
|
273
|
+
|
|
274
|
+
Not verified: Linux (the oracle platform statements stay `unverified`); only the declared exploit scenario and functional cases are
|
|
275
|
+
exercised, never the patch's correctness elsewhere.
|
|
276
|
+
|
|
277
|
+
## One projection for every interface, advisory/gating separation, conformance (X-206, X-207, X-208)
|
|
278
|
+
|
|
279
|
+
Same posture as the sections above: consumed, not wired into the default scan, every output addition additive and present only
|
|
280
|
+
when a verification record is. Suites: `test/verification/{interface-equivalence,advisory-gating,oracle-conformance}.test.js`
|
|
281
|
+
(`npm run test:verification`). Docs: `docs/guides/verification-schema-migration.md`, `docs/guides/verification-oracle-conformance.md`.
|
|
282
|
+
|
|
283
|
+
**`verification/projection.js` (X-206).** `projectVerification(record, { replay })` is the ONE place a record becomes something a
|
|
284
|
+
person or another tool reads: state, scope, oracle, evidence ids, replay prerequisites (derived from the record, plus the typed
|
|
285
|
+
ones a replay attempt reported), a what-was-verified / what-was-not summary, the legacy boolean view, and `text` lines. The JSON
|
|
286
|
+
report (`report/index.js` `normalizeFindings`), the CLI and Markdown reports (`verificationBlock`), MCP `explain_finding`,
|
|
287
|
+
`verify_fix` and `apply_fix`, and the autopilot response (`serializeAutopilotResult`, used by `scripts/autopilot.mjs --json`) all
|
|
288
|
+
call it; none formats its own verification text. The key is **`verificationView`**, never `verification`: a finding's existing
|
|
289
|
+
`verification` field is the producer/verifier separation record (`verification-separation.js`) and a first draft of this work
|
|
290
|
+
collided with it. An invalid record yields `verificationView: null` plus `verificationViewErrors`, never a guessed state. The text
|
|
291
|
+
never says "safe" or "fixed" for a partial result (a lint-style test covers every state, every repair status and the wording the real
|
|
292
|
+
surfaces emit; the fix-verify leg's native status word `fixed` is deliberately not echoed into a record reason). `verificationCoverage`
|
|
293
|
+
wraps `trustedNegativeDenominator`. Previous output schemas are pinned in `test/fixtures/verification-compat/`.
|
|
294
|
+
|
|
295
|
+
**`verification/advisory-state.js`, `verification/hypothesis-promotion.js` (X-207).** Hunt (`discovery/`) is advisory.
|
|
296
|
+
`writeAdvisoryState` is the only way advisory code writes: a closed file-name allowlist (the one hunt memory file), authoritative names
|
|
297
|
+
refused, write to a temp file and rename (a symlink or hard link planted at the target is replaced, never written through), the state
|
|
298
|
+
directory must resolve inside the project root. `discovery/memory.js` `saveMemory` uses it. `normalizeFindings` excludes any hunt
|
|
299
|
+
hypothesis (`parser: DISCOVERY` or a `discovery` object) from every finding list and exit code and records `advisoryExcluded`.
|
|
300
|
+
`promoteHypothesis({ hypothesis, result, policy })` is the only crossing: it verifies (not just checks presence of) a receipt issued by
|
|
301
|
+
`runOracle` (`isIssuedReceipt`), bound to the hypothesis and an exact commit and to a valid record settled `confirmed` at the
|
|
302
|
+
`runtime-confirmed` level, applies an EXPLICIT policy (fail-closed on an unknown key; the receipt rules are mandatory and cannot be
|
|
303
|
+
waived; `minConfidence`/`minAgreement` can only add a requirement), reuses `verification-separation.js` for hunter != verifier, and
|
|
304
|
+
returns a frozen audit record for every decision (`promoted`, `rejected`, `unsupported`, `inconclusive`) with no clock in it.
|
|
305
|
+
`runDiscovery` calls it only when `opts.promote = { policy, verify }` is given. The audit record is returned, not persisted:
|
|
306
|
+
persisting needs an artifact-registry classification and a signing domain, which are not decided here.
|
|
307
|
+
|
|
308
|
+
**`oracles/conformance.js` and `scripts/verification-conformance-check.mjs` (X-208).** One contract over every registered adapter:
|
|
309
|
+
static (class scope, budgets under `BUDGET_CEILINGS`, negative controls with an on-disk fixture, verifier-side evidence logic bound by
|
|
310
|
+
a digest, fixtures and logic pinned in `test/fixtures/oracles/conformance-pins.json`) and execution (state mappings, issued and frozen
|
|
311
|
+
receipts, three tamper attempts, an unavailable prerequisite, cancellation, replay). Wired into `scripts/release-check.mjs`
|
|
312
|
+
(`verification-conformance-gate`, in `RELEASE_GROUPS['benches-b']`) and, static half only, the pre-push gate
|
|
313
|
+
(`verification-conformance-static`). Where the boundary cannot run, execution is reported `not-run`, never passed; `--require-execution`
|
|
314
|
+
makes that a failure. A new adapter must be pinned deliberately (`--update-pins`).
|
|
315
|
+
|
|
142
316
|
## Execution-proof tiers (R2)
|
|
143
317
|
|
|
144
318
|
`proof-tier.js` + `execution-proof.js` add a fourth axis to a finding's
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// The recommendation mappings and the capability inventory that baseline capture
|
|
2
|
+
// (CORE-001) records. Pure data. Every path is relative to the repository root and
|
|
3
|
+
// is VERIFIED against the checkout at capture time: a path that does not exist is
|
|
4
|
+
// reported as a problem, never carried as if it did.
|
|
5
|
+
//
|
|
6
|
+
// Status vocabulary (one per capability, never combined):
|
|
7
|
+
// implemented the capability exists, has a source path and a test or artifact,
|
|
8
|
+
// and no gap against the differentiation PRD is known.
|
|
9
|
+
// partial it exists and is tested, and `gap` names exactly what the PRD
|
|
10
|
+
// still needs on top of it.
|
|
11
|
+
// unsupported the PRD calls for it and the checkout does not provide it; `source`
|
|
12
|
+
// is the existing extension point it would attach to, `evidence` the
|
|
13
|
+
// test that covers that neighbour, and `gap` says what is absent.
|
|
14
|
+
// unmeasured it exists but no current-revision measurement of it is recorded;
|
|
15
|
+
// `evidence` is the artifact that exists and `gap` says why it is not a
|
|
16
|
+
// current measurement.
|
|
17
|
+
//
|
|
18
|
+
// This is a statement about what was inspected, not a quality score. Moving an
|
|
19
|
+
// entry to a stronger status needs the new source and evidence paths to land first.
|
|
20
|
+
|
|
21
|
+
export const RECOMMENDATION_MAPPINGS = Object.freeze([
|
|
22
|
+
{
|
|
23
|
+
n: 1, title: 'Refresh real-code evaluation and repair measured misses', priority: 'P0', slice: 'QA-001..QA-008',
|
|
24
|
+
extensionPoints: ['bench/independent', 'scanner/src/posture/accuracy-scorecard.js', 'scripts/scorecard.mjs', 'docs/scorecard.json'],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
n: 2, title: 'Unify verification and expand trusted runtime oracles', priority: 'P0', slice: 'X-201..X-208',
|
|
28
|
+
extensionPoints: ['scanner/src/posture/fix-verify.js', 'scanner/src/posture/execution-proof.js', 'scanner/src/posture/verifier.js', 'scanner/src/sandbox/index.js', 'scanner/src/posture/autopilot.js', 'scanner/src/mcp/tools.js'],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
n: 3, title: 'Add a deployment-aware Code Boundaries graph', priority: 'P1', slice: 'X-301..X-308',
|
|
32
|
+
extensionPoints: ['scanner/src/lineage/runtime-observation.js', 'scanner/src/lineage/observation-adapters.js', 'scanner/src/lineage/observation-correlation.js', 'scanner/src/lineage/cross-repo-link.js', 'scanner/src/lineage/federation-loader.js', 'scanner/src/lineage/drift-policy.js'],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
n: 4, title: 'Execute tenant and business invariants', priority: 'P1', slice: 'X-401..X-408',
|
|
36
|
+
extensionPoints: ['scanner/src/posture/business-logic.js', 'scanner/src/posture/logic-claims.js', 'scanner/src/posture/specification-mining.js', 'scanner/src/discovery'],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
n: 5, title: 'Enforce coding-agent capabilities', priority: 'P1', slice: 'X-501..X-508',
|
|
40
|
+
extensionPoints: ['hooks/pre-bash-guard.js', 'hooks/pre-edit-bodyguard.js', 'hooks/dispatch-pre-tool.js', 'scanner/src/egress/policy.js', 'scanner/src/egress/redact.js', 'scanner/src/egress/audit.js', 'scanner/src/sandbox/index.js', 'scanner/src/mcp/server.js'],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
n: 6, title: 'Calibrate model routing against outcomes', priority: 'P2', slice: 'X-601..X-608',
|
|
44
|
+
extensionPoints: ['scanner/src/posture/model-routing.js', 'scanner/src/posture/model-trust.js', 'scanner/src/posture/cache-economics.js', 'scanner/src/posture/provider-catalog.js'],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
n: 7, title: 'Deliver portable release assurance and resumable portfolios', priority: 'P2', slice: 'X-701..X-708',
|
|
48
|
+
extensionPoints: ['scanner/src/posture/fleet.js', 'scanner/src/posture/scan-checkpoint.js', 'scanner/src/posture/attestation.js', 'scanner/src/posture/evidence-bundle.js', 'scanner/src/posture/integrity.js', 'scanner/src/posture/retention-policy.js'],
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
const t = (p) => ({ kind: 'test', path: p });
|
|
53
|
+
const a = (p) => ({ kind: 'artifact', path: p });
|
|
54
|
+
|
|
55
|
+
export const CAPABILITY_INVENTORY = Object.freeze([
|
|
56
|
+
{
|
|
57
|
+
id: 'poc-replay', workstream: 2, title: 'Proof-of-concept generation and confined replay',
|
|
58
|
+
status: 'partial',
|
|
59
|
+
source: ['scanner/src/posture/poc-generator.js', 'scanner/src/posture/poc-inprocess.js', 'scanner/src/posture/execution-proof.js', 'scanner/src/posture/proof-tier.js'],
|
|
60
|
+
entryPoints: [{ path: 'scanner/src/posture/execution-proof.js', symbol: 'proveFinding' }, { path: 'scanner/src/posture/proof-tier.js', symbol: 'attachProofTier' }],
|
|
61
|
+
evidence: [t('scanner/test/poc-generator.test.js'), t('scanner/test/execution-proof.test.js'), t('scanner/test/proof-artifact.test.js')],
|
|
62
|
+
gap: 'replay is JavaScript/taint oriented and records a proof tier on the finding; there is no class-specific oracle adapter, no patched-negative replay, and no single verification record',
|
|
63
|
+
prd: ['X-201', 'X-202', 'X-203', 'X-204', 'X-205'],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'fix-verification', workstream: 2, title: 'Fix verification (rescan, lint, tests, honesty gate, PoC re-check)',
|
|
67
|
+
status: 'partial',
|
|
68
|
+
source: ['scanner/src/posture/fix-verify.js', 'scanner/src/posture/fix-verify-loop.js', 'scanner/src/fix/apply-fix-service.js', 'scanner/src/posture/fix-honesty-gate.js'],
|
|
69
|
+
entryPoints: [{ path: 'scanner/src/posture/fix-verify.js', symbol: 'verifyFix' }, { path: 'scanner/src/fix/apply-fix-service.js', symbol: 'applyVerifiedFix' }],
|
|
70
|
+
evidence: [t('scanner/test/fix-verify-loop.test.js'), t('scanner/test/fix-verify-tests.test.js'), t('scanner/test/apply-fix-service.test.js'), t('scanner/test/fix-honesty-gate.test.js')],
|
|
71
|
+
gap: 'results are per-surface shapes, not one versioned record; original-positive, patched-negative and functional-regression evidence are not bound together by digest',
|
|
72
|
+
prd: ['X-201', 'X-204', 'X-206'],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'verifier-separation', workstream: 2, title: 'Independent verifier and verification separation',
|
|
76
|
+
status: 'partial',
|
|
77
|
+
source: ['scanner/src/posture/verifier.js', 'scanner/src/posture/verification-separation.js', 'scanner/src/posture/verifier-target.js', 'scanner/src/posture/verifier-ephemeral.js'],
|
|
78
|
+
entryPoints: [],
|
|
79
|
+
evidence: [t('scanner/test/verifier.test.js'), t('scanner/test/verifier-independence.test.js'), t('scanner/test/verification-separation.test.js')],
|
|
80
|
+
gap: 'separation is enforced for the existing verifier path; key and label isolation for the new oracle workers is the CORE-003 trust-boundary work',
|
|
81
|
+
prd: ['CORE-003', 'X-202'],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'sandbox-confinement', workstream: 2, title: 'Confinement sandbox (namespace, userspace and disabled backends)',
|
|
85
|
+
status: 'partial',
|
|
86
|
+
source: ['scanner/src/sandbox/index.js', 'scanner/src/sandbox/capabilities.js', 'scanner/src/sandbox/limits.js', 'scanner/src/sandbox/backend-namespace.js', 'scanner/src/sandbox/backend-userspace.js', 'scanner/src/sandbox/backend-disabled.js'],
|
|
87
|
+
entryPoints: [{ path: 'scanner/src/sandbox/index.js', symbol: 'runConfined' }],
|
|
88
|
+
evidence: [t('scanner/test/sandbox.test.js'), t('scanner/test/sandbox-escape.test.js')],
|
|
89
|
+
gap: 'isolation is probed per backend; descendant-process cleanup, read confinement and per-backend active probes are the CORE-003 work, and enforcement is only advertised on Linux',
|
|
90
|
+
prd: ['CORE-003', 'X-502', 'X-503'],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'runtime-observation-imports', workstream: 3, title: 'Runtime observation imports and correlation',
|
|
94
|
+
status: 'partial',
|
|
95
|
+
source: ['scanner/src/lineage/runtime-observation.js', 'scanner/src/lineage/observation-adapters.js', 'scanner/src/lineage/observation-store.js', 'scanner/src/lineage/observation-correlation.js', 'scanner/src/posture/telemetry-ingest.js'],
|
|
96
|
+
entryPoints: [{ path: 'scanner/src/lineage/runtime-observation.js', symbol: 'validateRuntimeObservation' }, { path: 'scanner/src/lineage/observation-store.js', symbol: 'persistObservationImport' }],
|
|
97
|
+
evidence: [t('scanner/test/lineage/runtime-observation.test.js'), t('scanner/test/lineage/observation-adapters.test.js'), t('scanner/test/lineage/observation-store.test.js'), t('scanner/test/lineage/observation-correlation.test.js')],
|
|
98
|
+
gap: 'one adapter (native-jsonl) is implemented; observations corroborate lineage edges but do not yet bind to vulnerability hypotheses, and freshness and sampling are not modelled as path states',
|
|
99
|
+
prd: ['X-302', 'X-303', 'X-305'],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'cross-repo-federation-drift', workstream: 3, title: 'Cross-repository links, federation and drift policy',
|
|
103
|
+
status: 'implemented',
|
|
104
|
+
source: ['scanner/src/lineage/cross-repo-link.js', 'scanner/src/lineage/federation-loader.js', 'scanner/src/lineage/drift-policy.js', 'scanner/src/lineage/graph-diff.js'],
|
|
105
|
+
entryPoints: [{ path: 'scanner/src/lineage/cross-repo-link.js', symbol: 'validateCrossRepoLink' }],
|
|
106
|
+
evidence: [t('scanner/test/lineage/cross-repo-link.test.js'), t('scanner/test/lineage/federation-loader.test.js'), t('scanner/test/lineage/drift-policy.test.js')],
|
|
107
|
+
gap: null,
|
|
108
|
+
prd: ['X-304', 'X-306'],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'business-logic-claims', workstream: 4, title: 'Business-logic detection, logic claims and specification mining',
|
|
112
|
+
status: 'partial',
|
|
113
|
+
source: ['scanner/src/posture/business-logic.js', 'scanner/src/posture/logic-claims.js', 'scanner/src/posture/specification-mining.js'],
|
|
114
|
+
entryPoints: [],
|
|
115
|
+
evidence: [t('scanner/test/business-logic.test.js'), t('scanner/test/logic-claims.test.js'), t('scanner/test/phase3-v3.test.js')],
|
|
116
|
+
gap: 'claims are advisory findings; there are no declarative approved invariants and no bounded stateful scenario execution',
|
|
117
|
+
prd: ['X-401', 'X-402', 'X-403', 'X-404'],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: 'stateful-invariant-execution', workstream: 4, title: 'Approved invariants, stateful scenarios, state oracles and sequence shrinking',
|
|
121
|
+
status: 'unsupported',
|
|
122
|
+
source: ['scanner/src/posture/logic-claims.js', 'scanner/src/discovery'],
|
|
123
|
+
entryPoints: [],
|
|
124
|
+
evidence: [t('scanner/test/logic-claims.test.js')],
|
|
125
|
+
gap: 'no executable invariant contract, approval state, scenario generator, durable-effect oracle or minimizer exists in the checkout',
|
|
126
|
+
prd: ['X-401', 'X-403', 'X-404', 'X-405'],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 'egress-policy-redaction-audit', workstream: 5, title: 'Central egress policy, outbound redaction and tamper-evident audit',
|
|
130
|
+
status: 'implemented',
|
|
131
|
+
source: ['scanner/src/egress/policy.js', 'scanner/src/egress/redact.js', 'scanner/src/egress/audit.js'],
|
|
132
|
+
entryPoints: [{ path: 'scanner/src/egress/policy.js', symbol: 'evaluateEgress' }, { path: 'scanner/src/egress/redact.js', symbol: 'redactPayload' }, { path: 'scanner/src/egress/audit.js', symbol: 'recordEgressCall' }],
|
|
133
|
+
evidence: [t('scanner/test/egress-policy.test.js'), t('scanner/test/egress-redact.test.js'), t('scanner/test/egress-audit.test.js'), t('scanner/test/egress-policy-completeness.test.js')],
|
|
134
|
+
gap: null,
|
|
135
|
+
prd: ['CORE-004', 'X-504'],
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 'agent-hooks', workstream: 5, title: 'Pre-edit, pre-bash and dispatch hooks',
|
|
139
|
+
status: 'partial',
|
|
140
|
+
source: ['hooks/pre-bash-guard.js', 'hooks/pre-edit-bodyguard.js', 'hooks/dispatch-pre-tool.js', 'hooks/hooks.json'],
|
|
141
|
+
entryPoints: [],
|
|
142
|
+
evidence: [t('scanner/test/pre-bash-guard.test.js'), t('scanner/test/bodyguard.test.js'), t('scanner/test/dispatch-pre-tool.test.js')],
|
|
143
|
+
gap: 'hooks explain and advise at the prompt layer; no runner mediates filesystem, command or network access, so a hook response is not an enforcement receipt',
|
|
144
|
+
prd: ['X-501', 'X-502', 'X-505', 'X-507'],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'mcp-server', workstream: 2, title: 'MCP server tools (including the write-gated fix tools)',
|
|
148
|
+
status: 'partial',
|
|
149
|
+
source: ['scanner/src/mcp/server.js', 'scanner/src/mcp/tools.js', 'scanner/src/mcp/validate.js', 'scanner/src/mcp/audit.js'],
|
|
150
|
+
entryPoints: [],
|
|
151
|
+
evidence: [t('scanner/test/mcp.test.js'), t('scanner/test/mcp-audit.test.js'), t('scanner/test/mcp-protocol-smoke.test.js')],
|
|
152
|
+
gap: 'tool results are not yet emitted as the unified verification record',
|
|
153
|
+
prd: ['X-206'],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 'model-routing-and-trust', workstream: 6, title: 'Model routing, measured trust, cache economics and provider catalog',
|
|
157
|
+
status: 'partial',
|
|
158
|
+
source: ['scanner/src/posture/model-routing.js', 'scanner/src/posture/model-trust.js', 'scanner/src/posture/cache-economics.js', 'scanner/src/posture/provider-catalog.js'],
|
|
159
|
+
entryPoints: [{ path: 'scanner/src/posture/model-trust.js', symbol: 'createTrustLedger' }, { path: 'scanner/src/posture/model-routing.js', symbol: 'routeModelWithTrust' }],
|
|
160
|
+
evidence: [t('scanner/test/model-routing.test.js'), t('scanner/test/model-trust.test.js'), t('scanner/test/cache-economics.test.js'), t('scanner/test/providers.test.js'), a('bench/router-replay/baseline.json')],
|
|
161
|
+
gap: 'trust is a per-key miss-rate ledger; there are no adjudicated task strata, calibrated quality intervals, shadow validation or drift circuit breakers',
|
|
162
|
+
prd: ['X-601', 'X-603', 'X-604', 'X-605'],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'fleet-checkpoints', workstream: 7, title: 'Fleet runs and scan checkpoints',
|
|
166
|
+
status: 'partial',
|
|
167
|
+
source: ['scanner/src/posture/fleet.js', 'scanner/src/posture/scan-checkpoint.js', 'scripts/fleet.mjs'],
|
|
168
|
+
entryPoints: [{ path: 'scanner/src/posture/scan-checkpoint.js', symbol: 'openCheckpoint' }],
|
|
169
|
+
evidence: [t('scanner/test/fleet.test.js'), t('scanner/test/scan-checkpoint.test.js')],
|
|
170
|
+
gap: 'checkpoints resume a single scan; there are no durable leased work units, dependency-hash invalidation or portfolio budgets',
|
|
171
|
+
prd: ['X-704', 'X-705', 'X-706'],
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: 'attestation-and-evidence-bundles', workstream: 7, title: 'Run attestation, signed per-finding evidence bundles, integrity and retention',
|
|
175
|
+
status: 'partial',
|
|
176
|
+
source: ['scanner/src/posture/attestation.js', 'scanner/src/posture/evidence-bundle.js', 'scanner/src/posture/integrity.js', 'scanner/src/posture/retention-policy.js'],
|
|
177
|
+
entryPoints: [{ path: 'scanner/src/posture/evidence-bundle.js', symbol: 'signEvidenceBundle' }, { path: 'scanner/src/posture/attestation.js', symbol: 'computeRunAttestation' }],
|
|
178
|
+
evidence: [t('scanner/test/attestation.test.js'), t('scanner/test/evidence-bundle.test.js'), t('scanner/test/retention-policy.test.js'), t('scanner/test/verify-attestation-cli.test.js')],
|
|
179
|
+
gap: 'bundles are per finding with a local signer; there is no release assurance manifest, portable package or explicit trust-root policy',
|
|
180
|
+
prd: ['X-701', 'X-702', 'X-703', 'CORE-003'],
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: 'accuracy-scorecard', workstream: 1, title: 'Published accuracy scorecard and corpus replay',
|
|
184
|
+
status: 'implemented',
|
|
185
|
+
source: ['scanner/src/posture/accuracy-scorecard.js', 'scripts/scorecard.mjs'],
|
|
186
|
+
entryPoints: [],
|
|
187
|
+
evidence: [t('scanner/test/accuracy-scorecard.test.js'), t('scanner/test/scorecard.test.js'), a('docs/scorecard.json')],
|
|
188
|
+
gap: null,
|
|
189
|
+
prd: ['QA-004'],
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 'independent-accuracy-current-engine', workstream: 1, title: 'Current-engine accuracy on independent real code',
|
|
193
|
+
status: 'unmeasured',
|
|
194
|
+
source: ['bench/independent/runner.mjs', 'bench/independent/manifest.json'],
|
|
195
|
+
entryPoints: [],
|
|
196
|
+
evidence: [a('docs/scorecard.json'), a('docs/INDEPENDENT_POPULATION_ROOT_CAUSE.md')],
|
|
197
|
+
gap: 'the recorded independent result belongs to an older engine revision; no current-engine adjudicated measurement exists in the checkout',
|
|
198
|
+
prd: ['QA-001', 'QA-002', 'QA-003'],
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: 'loop-controller', workstream: 'foundation', title: 'Supervised background implementation controller (Haskell/Nix profile)',
|
|
202
|
+
status: 'partial',
|
|
203
|
+
source: ['scripts/loop-engineering/run.mjs', 'scripts/loop-engineering/profiles/haskell-nix.json'],
|
|
204
|
+
entryPoints: [],
|
|
205
|
+
evidence: [t('scripts/loop-engineering/test/loop-manifest.test.js'), t('scripts/loop-engineering/test/loop-watchdog.test.js'), t('scripts/loop-engineering/test/loop-recovery.test.js')],
|
|
206
|
+
gap: 'only the Haskell/Nix profile exists; the assurance-differentiation profile and its protected acceptance suites are not present',
|
|
207
|
+
prd: ['LOOP-001', 'LOOP-002', 'LOOP-003'],
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: 'lineage-graph', workstream: 3, title: 'Data Flow Explorer lineage graph (DataFlowGraph v1)',
|
|
211
|
+
status: 'implemented',
|
|
212
|
+
source: ['scanner/src/lineage/graph-builder.js', 'scanner/src/lineage/ids.js', 'scanner/src/lineage/schema.js', 'scanner/src/lineage/dataflow-graph.schema.json'],
|
|
213
|
+
entryPoints: [{ path: 'scanner/src/lineage/ids.js', symbol: 'graphId' }],
|
|
214
|
+
evidence: [t('scanner/test/lineage/schema.test.js'), t('scanner/test/lineage/ids.test.js')],
|
|
215
|
+
gap: null,
|
|
216
|
+
prd: ['X-301'],
|
|
217
|
+
},
|
|
218
|
+
]);
|