@blamejs/exceptd-skills 0.12.7 → 0.12.8

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.
Files changed (64) hide show
  1. package/AGENTS.md +14 -0
  2. package/CHANGELOG.md +67 -0
  3. package/bin/exceptd.js +189 -52
  4. package/data/_indexes/_meta.json +37 -37
  5. package/data/_indexes/activity-feed.json +26 -26
  6. package/data/_indexes/catalog-summaries.json +8 -8
  7. package/data/_indexes/chains.json +238 -0
  8. package/data/_indexes/frequency.json +63 -5
  9. package/data/_indexes/jurisdiction-map.json +13 -3
  10. package/data/_indexes/section-offsets.json +881 -845
  11. package/data/_indexes/summary-cards.json +2 -2
  12. package/data/_indexes/token-budget.json +145 -125
  13. package/data/atlas-ttps.json +189 -1
  14. package/data/cwe-catalog.json +290 -1
  15. package/data/d3fend-catalog.json +163 -1
  16. package/data/framework-control-gaps.json +243 -0
  17. package/data/playbooks/containers.json +23 -5
  18. package/data/playbooks/cred-stores.json +9 -9
  19. package/data/playbooks/crypto.json +8 -8
  20. package/data/playbooks/hardening.json +46 -10
  21. package/data/playbooks/library-author.json +16 -20
  22. package/data/playbooks/runtime.json +7 -7
  23. package/data/playbooks/sbom.json +11 -11
  24. package/data/playbooks/secrets.json +4 -4
  25. package/data/rfc-references.json +144 -0
  26. package/lib/refresh-external.js +25 -5
  27. package/lib/schemas/skill-frontmatter.schema.json +2 -2
  28. package/manifest-snapshot.json +1 -1
  29. package/manifest.json +67 -67
  30. package/package.json +2 -1
  31. package/sbom.cdx.json +6 -6
  32. package/scripts/check-sbom-currency.js +87 -0
  33. package/scripts/check-test-coverage.README.md +148 -0
  34. package/scripts/check-test-coverage.js +455 -0
  35. package/scripts/hooks/pre-commit.sh +19 -0
  36. package/scripts/predeploy.js +16 -30
  37. package/skills/age-gates-child-safety/skill.md +3 -0
  38. package/skills/ai-attack-surface/skill.md +4 -1
  39. package/skills/ai-c2-detection/skill.md +6 -1
  40. package/skills/ai-risk-management/skill.md +3 -0
  41. package/skills/api-security/skill.md +3 -0
  42. package/skills/attack-surface-pentest/skill.md +3 -0
  43. package/skills/cloud-security/skill.md +3 -0
  44. package/skills/container-runtime-security/skill.md +3 -0
  45. package/skills/coordinated-vuln-disclosure/skill.md +8 -1
  46. package/skills/defensive-countermeasure-mapping/skill.md +1 -1
  47. package/skills/dlp-gap-analysis/skill.md +3 -0
  48. package/skills/email-security-anti-phishing/skill.md +9 -1
  49. package/skills/identity-assurance/skill.md +6 -1
  50. package/skills/incident-response-playbook/skill.md +8 -2
  51. package/skills/kernel-lpe-triage/skill.md +24 -4
  52. package/skills/mcp-agent-trust/skill.md +4 -1
  53. package/skills/mlops-security/skill.md +3 -0
  54. package/skills/ot-ics-security/skill.md +3 -0
  55. package/skills/rag-pipeline-security/skill.md +3 -0
  56. package/skills/sector-energy/skill.md +3 -0
  57. package/skills/sector-federal-government/skill.md +3 -0
  58. package/skills/sector-financial/skill.md +3 -0
  59. package/skills/sector-healthcare/skill.md +3 -0
  60. package/skills/security-maturity-tiers/skill.md +19 -1
  61. package/skills/skill-update-loop/skill.md +32 -0
  62. package/skills/supply-chain-integrity/skill.md +3 -0
  63. package/skills/threat-modeling-methodology/skill.md +3 -0
  64. package/skills/webapp-security/skill.md +3 -0
package/AGENTS.md CHANGED
@@ -34,6 +34,20 @@ Also read [CONTEXT.md](CONTEXT.md) for a complete orientation to the skill syste
34
34
 
35
35
  14. **Primary-source IoC review** — Any CVE entry in `data/cve-catalog.json` whose `poc_available: true` AND whose exploit code is publicly available (published PoC repo, vendor advisory with attached payload, researcher blog with reproducer) must include `iocs` populated from a line-level cross-reference of the published source — not from secondary-source paraphrase. The `iocs` block records which IoC categories were extracted (`payload_artifacts`, `persistence_artifacts`, `credential_paths_scanned`, `c2_indicators`, `host_recon`, `behavioral`, `runtime_syscall`, `kernel_trace`, `livepatch_gap`, `destructive`, `payload_content_patterns`, `supply_chain_entry_vectors`), and each IoC must be traceable to a specific source URL or commit hash. v0.12.6 audit reviewed CVE-2026-45321 (Mini Shai-Hulud), CVE-2026-31431 (Copy Fail / Dirty Pipe / Dirty COW family), CVE-2026-43284 + CVE-2026-43500 (Dirty Frag pair), CVE-2025-53773 (Copilot YOLO mode), and CVE-2026-30615 (Windsurf MCP) against primary sources from Aikido, StepSecurity, Socket, Wiz, Datadog, Sysdig, Trail of Bits, Invariant Labs, Embrace the Red, NVD, MSRC. Catalog updates landed in v0.12.6 changelog. Skipping this audit is equivalent to shipping "untested security advice" — the IoC list IS the operator-facing detection contract.
36
36
 
37
+ 15. **Test coverage on every diff** — Every feature change (added, removed, or modified) must land with a covering test reference in the same PR. The shapes the gate enforces:
38
+
39
+ | Change | Required test reference |
40
+ | ----------------------------------------------------- | -------------------------------------------------------------------------------- |
41
+ | New / removed CLI verb in `bin/exceptd.js` | Quoted verb literal in a `tests/*.test.js` file |
42
+ | New / removed CLI flag | Flag literal (e.g. `--my-flag`) somewhere under `tests/` |
43
+ | New / removed / renamed `module.exports` identifier | `require('…/<lib>')` plus a reference to the identifier in `tests/` |
44
+ | New `phases.detect.indicators[].id` in a playbook | Quoted indicator id literal in `tests/e2e-scenarios/*/expect.json` or `tests/*.test.js` |
45
+ | New / changed `iocs` field on a CVE entry | CVE id and the word `iocs` in the same test file |
46
+
47
+ Mechanical enforcement lives in `scripts/check-test-coverage.js` and runs as the 15th gate of `npm run predeploy` (also the `Diff coverage` job in `ci.yml`). Docs (`*.md`), workflow YAML, and skill body changes are allowlisted — skill bodies are covered by the Ed25519 signature gate (Hard Rule #13), workflows surface a manual-review flag rather than a hard finding. Whitespace-only diffs are ignored.
48
+
49
+ The gate ships in v0.12.8 as `--warn-only` during the rollout window; it flips to blocking in v0.12.9. Once blocking, never bypass with `--no-verify` or `--warn-only` — add the covering test first. This rule is additive to Hard Rule #11 (no-MVP ban): a new playbook indicator or CLI surface that ships without a regression test is the same shape of incomplete-feature ship that #11 forbids, applied to the test layer.
50
+
37
51
  ---
38
52
 
39
53
  ## Seven-phase playbook contract
package/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.8 — 2026-05-13
4
+
5
+ **Patch: comprehensive audit pass — CLI surface fixes, catalog completeness, test infrastructure hardening, AGENTS.md Hard Rule #15.**
6
+
7
+ ### Hard Rule #15 — Test coverage on every diff
8
+
9
+ `AGENTS.md` adds a fifteenth hard rule: every CLI verb, CLI flag, `module.exports` identifier, playbook `phases.detect.indicators[].id`, or CVE `iocs` field change must land with a covering test reference in the same PR. Enforcement lives in `scripts/check-test-coverage.js`, wired as the 15th `npm run predeploy` gate and the `Diff coverage` job in `ci.yml`. Ships `--warn-only` for one release cycle then flips blocking in v0.12.9. Docs, workflow YAML, and skill body changes are allowlisted; whitespace-only diffs are ignored.
10
+
11
+ ### CLI surface — exit-code, dispatcher, and ingest
12
+
13
+ `run --ci`, `run --all`, and `ai-run --stream` previously called `process.exit(N)` immediately after `emit()` writes to stdout — the v0.11.10 #100 truncation class. All three sites now use `process.exitCode = N; return;` so buffered async stdout fully drains before the event loop ends. The `ai-run` streaming handler additionally pauses stdin on completion so further callbacks cannot re-enter after the final frame.
14
+
15
+ The deprecation banner for legacy verbs now fires for every alias in `LEGACY_VERB_REPLACEMENTS`, not just the subset routed through `PLAYBOOK_VERBS`. Operators running `scan`, `dispatch`, `currency`, `verify`, `validate-cves`, `validate-rfcs`, `watchlist`, `prefetch`, or `build-indexes` now see the same one-time banner pointing at the v0.11.0 replacement that `plan`, `govern`, `direct`, `look`, `ingest`, `reattest`, and `list-attestations` already surfaced.
16
+
17
+ `ingest` previously wrote its attestation via an inline `writeFileSync` that bypassed both the session-id collision refusal and the Ed25519 sidecar signing layer that `run` and `run --all` go through. Two `ingest` invocations with the same `--session-id` would silently clobber the audit trail and no `.sig` ever landed. Routed through `persistAttestation()` now — collision refusal and `maybeSignAttestation()` both apply.
18
+
19
+ Per-verb `--help` text expanded to cover surface that shipped undocumented: `ci --required <ids>`, `ci --max-rwep`, `ci --block-on-jurisdiction-clock`, `ci --evidence-dir`, `ci --format`, plus the full four-line exit-code matrix (0 PASS / 1 framework error / 2 detected / 3 ran-but-no-evidence / 4 blocked). `attest list` and `attest diff` subverbs added to the `attest --help` enumeration. `run --upstream-check`, `--strict-preconditions`, `--session-key`, `--air-gap`, `--force-overwrite` documented in the `run` block. `doctor --registry-check` and `doctor --fix` documented in the `doctor` block. `brief`, `lint`, `run-all`, `verify-attestation` gain per-verb help entries.
20
+
21
+ ### Catalog completeness — 47 new entries close cross-catalog dangling refs
22
+
23
+ Six ATLAS TTPs added to `data/atlas-ttps.json`: T0024 (Exfiltration via ML Inference API), T0044 (Full ML Model Access), T0048 (Erode ML Model Integrity), T0053 (LLM Plugin Compromise), T0055 (Unsecured Credentials), T0057 (LLM Data Leakage). All previously referenced by `data/cve-catalog.json` (CVE-2026-45321) and `data/dlp-controls.json` without a catalog entry.
24
+
25
+ Seventeen CWE entries added to `data/cwe-catalog.json`: CWE-250, 256, 284, 310, 312, 326, 328, 329, 330, 331, 338, 353, 426, 522, 759, 760, 916. All previously referenced by playbook `domain.cwe_refs` across `containers`, `cred-stores`, `crypto`, `crypto-codebase`, `ai-api`, `secrets`, `hardening`, `runtime`, and `library-author` without a catalog entry.
26
+
27
+ Eight D3FEND entries added to `data/d3fend-catalog.json`: D3-ANCI, D3-CAA, D3-CH, D3-EI, D3-FCR, D3-KBPI, D3-SCA, D3-SFA. All previously referenced by playbook `domain.d3fend_refs` without a catalog entry.
28
+
29
+ Ten framework-control-gap entries added to `data/framework-control-gaps.json`: NIS2-Art21-incident-handling, EU-AI-Act-Art-15, UK-CAF-A1/B2/C1/D1, AU-Essential-8-MFA/App-Hardening/Patch/Backup. Closes the Hard Rule #5 (global-first) gap for 23 skills that previously declared US-anchored `framework_gaps` only.
30
+
31
+ Twelve standards entries added to `data/rfc-references.json`: RFC-7489 (DMARC), RFC-6376 (DKIM), RFC-7208 (SPF), RFC-8616 (IDN email auth), RFC-8461 (MTA-STS), ISO-29147 + ISO-30111 (vulnerability disclosure + handling), RFC-9116 (security.txt), CSAF-2.0, RFC-6545 (RID), RFC-6546 (RID transport), RFC-7970 (IODEF v2). Schema (`lib/schemas/skill-frontmatter.schema.json`) + validator (`tests/rfc-refs.test.js`) extended to accept the broader standards-key shape (`RFC-`, `DRAFT-`, `ISO-`, `CSAF-`) alongside RFC numbers.
32
+
33
+ ### Playbook integrity — orphan close + indicator wiring
34
+
35
+ `library-author.json` `_meta.feeds_into` removed a dangling `compliance-theater` entry (no such playbook file exists); the remaining `framework` entry handles the same condition. `mcp.json` `domain.cve_refs` now lists CVE-2025-53773 alongside CVE-2026-30615 and CVE-2026-45321 — closes the Hard Rule #4 gap where the existing `copilot-yolo-mode-flag` and `copilot-chat-experimental-flags` indicators detected the CVE without the playbook claiming it.
36
+
37
+ Eight playbooks had artifacts collected in `phases.look.artifacts[]` that no indicator consumed — operator paid the collection cost, no detection ran. Containers (9 orphans), cred-stores (9), runtime (11), crypto (10), hardening (11), library-author (14), sbom (18), secrets (7) all now cite every collected artifact in at least one indicator. Six new indicators added (`psa-policy-permissive-or-absent` and `network-policies-absent-from-workload-namespace` in `containers`; `kernel-lockdown-none`, `sudoers-tty-pty-logging-absent`, `audit-rules-empty-or-skeletal`, `umask-permissive` in `hardening`) where existing detection logic conceptually consumed the artifact but no rule had been written.
38
+
39
+ ### Skill files — required-section closures, Hard Rule #5 sweep
40
+
41
+ `kernel-lpe-triage`, `security-maturity-tiers`, and `skill-update-loop` previously failed the Hard Rule #11 required-section contract. `kernel-lpe-triage` had a Compliance Theater Check embedded inside Analysis Procedure Step 5 but no top-level section; `security-maturity-tiers` had no Compliance Theater section at all; `skill-update-loop` was missing Threat Context and TTP Mapping. All three sections promoted to top-level with substantive content.
42
+
43
+ Twenty-three skills had US-anchored `framework_gaps` only (NIST + ISO + SOC2). Each gains EU + UK + AU tokens (`NIS2-Art21-incident-handling` / `EU-AI-Act-Art-15`, `UK-CAF-A1/B2/C1/D1`, `AU-Essential-8-MFA/App-Hardening/Patch/Backup` as the per-skill match dictates). `ai-c2-detection` `cwe_refs` populated with CWE-918. `email-security-anti-phishing` `rfc_refs` populated with RFC-7489/6376/7208/8616/8461. `identity-assurance` `d3fend_refs` populated with D3-MFA + D3-CSPP. `coordinated-vuln-disclosure` `rfc_refs` populated with ISO-29147/30111, RFC-9116, CSAF-2.0. `incident-response-playbook` `rfc_refs` populated with RFC-6545/6546/7970.
44
+
45
+ Four skills bump `last_threat_review` to 2026-05-13 to reflect post-v0.12.6 catalog state: `kernel-lpe-triage`, `ai-attack-surface`, `mcp-agent-trust`, `ai-c2-detection`. Four skills replace literal `xxx` placeholders in body text with explicit angle-bracket placeholders (`<patch-revision>`, `<sub-technique-id>`, `<advisory-number>`) so future Rule #10 audits don't surface false positives.
46
+
47
+ ### Test infrastructure
48
+
49
+ The `cli()` test helper now routes attestations to a per-suite tempdir via `EXCEPTD_HOME` instead of writing to `~/.exceptd/attestations/`. Every prior `npm test` run had been accumulating attestations in the maintainer's real home dir without cleanup; tempdir routing fixes the structural class behind the v0.11.x→v0.12.4 sign regression. Helper factored to `tests/_helpers/cli.js` so it can be required by both `operator-bugs.test.js` and the new `cli-coverage.test.js`.
50
+
51
+ Twenty-eight previously-coincidence-passing assertions in `operator-bugs.test.js` strengthened: silent fall-through `if (data?.ok === false)` branches replaced with hard parse + shape checks first; `assert.notEqual(r.status, 0)` replaced with explicit exit-code pins (2 for format-rejected, 4 for blocked, etc.); `assert.ok(data)` replaced with field-shape assertions. Two coincidence-passes that hid real defects became actual findings:
52
+
53
+ - `refresh --no-network` on Windows + Node 25 surfaces a libuv `UV_HANDLE_CLOSING` assertion at worker-pool teardown after the prefetch summary flushes cleanly (exit 3221226505 / 0xC0000409). The summary contract is honored; the teardown crash is a Windows-libuv quirk. Test accepts both 0 and the Windows exit code so long as the stdout summary matches the strict numeric-breakdown regex.
54
+ - `refresh` pin sources `d3fend__d3fend-data__releases` and `mitre__cwe__releases` return HTTP 404 — surfaces as `2 error(s)` in every prefetch summary. Flagged for upstream catalog-pin work; not a regression introduced here.
55
+
56
+ `lib/refresh-external.js` now accepts `--catalog <path>` and honors `EXCEPTD_CVE_CATALOG` so tests can redirect catalog writes to a tempdir instead of mutating the shipped `data/cve-catalog.json`. Eight catalog-mutating tests in `operator-bugs.test.js` can now route to tempdirs.
57
+
58
+ Thirty-one new CLI happy-path tests in `tests/cli-coverage.test.js` exercise `brief` (all/scope/directives/phase), `discover`, `doctor` (all subchecks), `attest show/list/export`, `verify-attestation` alias, `run-all` alias, `framework-gap`, `report executive`, `validate-rfcs`, `ai-run` streaming JSONL (strict in-order assertion across all nine frames), `ci --max-rwep`, `ci --block-on-jurisdiction-clock`, `ci --evidence-dir`, `run --vex`, `run --diff-from-latest`, `run --force-stale`, `run --air-gap`, `run --session-key` (HMAC), and `refresh --indexes-only`.
59
+
60
+ Eight predeploy-gate meta-tests in `tests/predeploy-gates.test.js` stage known-bad state in tempdirs and assert each gate fires: verify-signatures (byte-flipped signature), lint-skills (missing required section), validate-catalog-meta (malformed `tlp`), sbom-currency (drift), validate-indexes (out-of-date entry), validate-vendor (modified vendored file), validate-package (missing file-allowlist entry), verify-shipped-tarball (skill body tampered post-signing — the v0.11.x→v0.12.4 regression class). Gate 10's inline `node -e` checker extracted to `scripts/check-sbom-currency.js` for testability; no behavior change.
61
+
62
+ Twelve new e2e scenarios in `tests/e2e-scenarios/09-secrets-aws-key` through `20-ai-api-openai-dotfile` exercise the twelve playbooks previously without e2e coverage (`secrets`, `kernel`, `library-author`, `crypto-codebase`, `mcp`, `framework`, `cred-stores`, `containers`, `runtime`, `hardening`, `crypto`, `ai-api`). All twenty scenarios pass via `npm run test:e2e`.
63
+
64
+ ### Repository
65
+
66
+ Dependabot grouping config added for the github-actions ecosystem: weekly version-update bumps now land as a single grouped PR instead of N parallel PRs against the same 14-gate CI matrix. Security-updates stay ungrouped so a single-action CVE surfaces as its own PR.
67
+
68
+ Test count: 386 → 418 (388 + 31 cli-coverage − accounting note: 8 predeploy-gates + 12 diff-coverage tests landed alongside the +31 CLI surface tests; some pre-existing tests resolved into fewer counted tests on suite reorganization). Predeploy gates: 14 → 15.
69
+
3
70
  ## 0.12.7 — 2026-05-13
4
71
 
5
72
  **Patch: two follow-on fixes to v0.12.6.**
package/bin/exceptd.js CHANGED
@@ -378,27 +378,29 @@ function main() {
378
378
  process.exit(0);
379
379
  }
380
380
 
381
+ // v0.12.8: emit the deprecation banner BEFORE branching on PLAYBOOK_VERBS
382
+ // so that legacy aliases routed through STANDALONE_VERBS or the orchestrator
383
+ // (scan, dispatch, currency, verify, validate-cves, validate-rfcs,
384
+ // watchlist, prefetch, build-indexes) also surface the rename.
385
+ // Previously the banner only fired for PLAYBOOK_VERBS-resident aliases
386
+ // (plan, govern, direct, look, ingest, reattest, list-attestations).
387
+ if (LEGACY_VERB_REPLACEMENTS[cmd] && !process.env.EXCEPTD_DEPRECATION_SHOWN) {
388
+ const ver = readPkgVersion();
389
+ const haveBrief = ver !== "unknown" && ver.match(/^(\d+)\.(\d+)/) && (parseInt(RegExp.$1, 10) > 0 || parseInt(RegExp.$2, 10) >= 11);
390
+ process.stderr.write(
391
+ `[exceptd] DEPRECATION: \`${cmd}\` is a v0.10.x verb. ` +
392
+ (haveBrief
393
+ ? `Prefer \`${LEGACY_VERB_REPLACEMENTS[cmd]}\` (available in this install, v${ver}). `
394
+ : `Upgrade to v0.11.0+ then use \`${LEGACY_VERB_REPLACEMENTS[cmd]}\` (currently installed: v${ver}). `) +
395
+ `Legacy verbs remain functional through this release; they will be removed in v0.13. ` +
396
+ `Suppress: export EXCEPTD_DEPRECATION_SHOWN=1.\n`
397
+ );
398
+ process.env.EXCEPTD_DEPRECATION_SHOWN = "1";
399
+ }
400
+
381
401
  // Seven-phase playbook verbs run in-process — they emit JSON to stdout
382
402
  // rather than dispatch to a script.
383
403
  if (PLAYBOOK_VERBS.has(cmd)) {
384
- // One-time deprecation banner per process when a legacy verb is invoked.
385
- if (LEGACY_VERB_REPLACEMENTS[cmd] && !process.env.EXCEPTD_DEPRECATION_SHOWN) {
386
- // Mention the installed version explicitly so an operator on v0.10.x
387
- // who reads "Prefer brief..." doesn't go looking for a verb that
388
- // doesn't exist in their install. v0.11.0+ has the replacement; v0.10.x
389
- // users see this with the explicit "upgrade to v0.11.0 first" note.
390
- const ver = readPkgVersion();
391
- const haveBrief = ver !== "unknown" && ver.match(/^(\d+)\.(\d+)/) && (parseInt(RegExp.$1, 10) > 0 || parseInt(RegExp.$2, 10) >= 11);
392
- process.stderr.write(
393
- `[exceptd] DEPRECATION: \`${cmd}\` is a v0.10.x verb. ` +
394
- (haveBrief
395
- ? `Prefer \`${LEGACY_VERB_REPLACEMENTS[cmd]}\` (available in this install, v${ver}). `
396
- : `Upgrade to v0.11.0+ then use \`${LEGACY_VERB_REPLACEMENTS[cmd]}\` (currently installed: v${ver}). `) +
397
- `Legacy verbs remain functional through this release; they will be removed in v0.13. ` +
398
- `Suppress: export EXCEPTD_DEPRECATION_SHOWN=1.\n`
399
- );
400
- process.env.EXCEPTD_DEPRECATION_SHOWN = "1";
401
- }
402
404
  dispatchPlaybook(cmd, rest);
403
405
  return;
404
406
  }
@@ -798,10 +800,24 @@ Flags:
798
800
  (code 2) when phases.detect.classification === 'detected'
799
801
  OR phases.analyze.rwep.adjusted >= rwep_threshold.escalate.
800
802
  Logs PASS/FAIL reason to stderr.
801
- --session-id <id> Reuse a specific session ID.
803
+ --upstream-check (v0.11.14) Opt-in: query npm registry for the latest
804
+ published @blamejs/exceptd-skills version before
805
+ detect. Warns to stderr (no exit-code change) when
806
+ the local install is behind, so an operator using a
807
+ stale catalog finds out before the run completes.
808
+ --strict-preconditions Escalate warn-level precondition failures to halt.
809
+ Without this flag, only on_fail=halt preconditions
810
+ block; warn-level surface in stderr but the run
811
+ proceeds. With it, any precondition_check returning
812
+ false fails the run and exits non-zero.
813
+ --session-id <id> Reuse a specific session ID. Collisions refused
814
+ unless --force-overwrite is also passed.
815
+ --force-overwrite Override the session-id collision refusal.
802
816
  --session-key <hex> HMAC sign the evidence_package with this key.
817
+ Output carries an 'hmac' field the verifier can check.
803
818
  --force-stale Override the threat_currency_score < 50 hard-block.
804
- --air-gap Honor air_gap_alternative paths.
819
+ --air-gap Honor air_gap_alternative paths in look.artifacts[]
820
+ and skip the network-touching collection variants.
805
821
  --pretty Indented JSON output.
806
822
 
807
823
  Attestation is persisted to .exceptd/attestations/<session_id>/ on every
@@ -835,12 +851,22 @@ newest-first, with truncated evidence_hash + capture timestamp + file path.`,
835
851
 
836
852
  Subverbs:
837
853
  attest show <sid> Emit the full (unredacted) attestation.
854
+ attest list Inventory every prior attestation under
855
+ ~/.exceptd/attestations/ (or EXCEPTD_HOME when set).
856
+ Filter with --playbook <id> or --since <ISO>. Newest
857
+ first; truncated evidence_hash + capture timestamp +
858
+ path per entry.
838
859
  attest export <sid> Emit redacted JSON suitable for audit submission.
839
860
  Strips raw artifact values; preserves evidence_hash,
840
861
  signature, classification, RWEP, remediation choice.
841
- --format csaf wraps the export in a CSAF envelope.
862
+ --format <csaf|sarif|openvex> wraps the export in the
863
+ named envelope (default: redacted JSON).
842
864
  attest verify <sid> Verify .sig sidecar against keys/public.pem.
843
865
  Reports tamper status per attestation file.
866
+ attest diff <sid> Diff <sid> against the most-recent prior attestation
867
+ for the same playbook, or against --against <other-sid>
868
+ for an explicit pair. Reports unchanged | drifted |
869
+ resolved per evidence_hash + classification deltas.
844
870
 
845
871
  All subverbs honor --pretty for indented JSON output.`,
846
872
  discover: `discover — context-aware playbook recommender (v0.11.0).
@@ -867,7 +893,20 @@ Subchecks:
867
893
  --currency Skill currency report (last_threat_review).
868
894
  --cves CVE catalog validation (offline view).
869
895
  --rfcs RFC catalog validation (offline view).
870
- (no flag) All four, plus signing-status (private key presence).
896
+ --registry-check (v0.11.14) Opt-in: query the npm registry for the
897
+ latest published version + days-since-publish.
898
+ Surfaces under checks.registry.{local_version,
899
+ published_version, same, behind, days_since_latest_publish}.
900
+ Off by default — keeps doctor offline-clean unless
901
+ asked.
902
+ --fix (v0.12.5) Attempt to auto-remediate detected gaps.
903
+ Currently scoped to: regenerate the local Ed25519
904
+ private key when keys/public.pem exists but
905
+ .keys/private.pem is absent. Does NOT modify any
906
+ file outside .keys/.
907
+ (no flag) All four subchecks above (sans --registry-check
908
+ unless explicitly requested), plus signing-status
909
+ (private key presence under .keys/).
871
910
 
872
911
  Flags:
873
912
  --json Emit JSON (default is human-readable text).
@@ -914,6 +953,9 @@ exit-code contract designed for one-line .github/workflows entries.
914
953
  Flags:
915
954
  --all Run every playbook.
916
955
  --scope <type> Filter: system | code | service | cross-cutting.
956
+ --required <ids> Comma-separated playbook ids that MUST run, even if
957
+ scope-detection would exclude them. Fails if a
958
+ required id is unknown.
917
959
  (no flag) Auto-detect scopes from cwd (same logic as run).
918
960
  --evidence <file> Submission bundle (multi-playbook shape).
919
961
  --evidence-dir <dir> Read <playbook-id>.json files from a directory.
@@ -921,11 +963,77 @@ Flags:
921
963
  --block-on-jurisdiction-clock
922
964
  Fail when any close.notification_actions started a
923
965
  regulatory clock (GDPR 72h, HIPAA breach, etc.).
924
- --pretty Indented JSON output.
966
+ --format <fmt> Output shape. Supported: json (default, single-line),
967
+ summary (5-field digest), markdown (human digest).
968
+ Bundles (csaf-2.0/sarif/openvex) live on per-run
969
+ attestations, not the aggregate ci verdict.
970
+ --json Force single-line JSON (overrides any TTY heuristics).
971
+ --pretty Indented JSON output (implies --json).
972
+
973
+ Exit codes:
974
+ 0 PASS All scoped playbooks ran and verdict is clean.
975
+ 1 Framework error Runner threw, unreadable evidence, etc.
976
+ 2 FAIL (detected) At least one playbook returned
977
+ classification=detected, OR rwep ≥ escalate, OR
978
+ --max-rwep cap exceeded.
979
+ 3 Ran-but-no-evidence Every result was inconclusive AND no evidence was
980
+ submitted (visibility gap — CI should fail loud).
981
+ 4 Blocked Result returned ok:false (preflight halt, missing
982
+ preconditions with on_fail=halt, etc.) OR
983
+ --block-on-jurisdiction-clock fired.
925
984
 
926
- Exit codes: 0 PASS, 2 FAIL (detected | rwep ≥ cap | clock started w/ block flag).
927
985
  Output: verb, session_id, playbooks_run, summary{total, detected,
928
- max_rwep_observed, jurisdiction_clocks_started, verdict}, results[].`,
986
+ max_rwep_observed, jurisdiction_clocks_started, verdict, fail_reasons[]},
987
+ results[].`,
988
+ brief: `brief [playbook] — unified info doc (v0.11.0).
989
+
990
+ Collapses the three info-only phases plan + govern + direct + look into a
991
+ single document. Phases 1-3 of the seven-phase contract are entirely
992
+ informational; brief reads them in one CLI invocation instead of three.
993
+
994
+ Modes:
995
+ brief Auto-detect playbooks for the cwd. Returns a list.
996
+ brief <playbook> Single-playbook brief with jurisdiction obligations
997
+ + threat context + preconditions + artifacts +
998
+ indicators.
999
+ brief --all Every shipped playbook.
1000
+ brief --scope <type> Filter: system | code | service | cross-cutting.
1001
+ brief <pb> --phase <p> Emit only the named phase (govern | direct | look).
1002
+ Compat for legacy callers.
1003
+
1004
+ Flags:
1005
+ --directives Expand directive metadata per playbook.
1006
+ --pretty Indented JSON output.
1007
+ --json Force single-line JSON.
1008
+
1009
+ Output (single-playbook): playbook_id, directives[], jurisdiction_obligations[],
1010
+ threat_context, preconditions[], artifacts[], indicators[].`,
1011
+ lint: `lint <playbook> <evidence-file> — pre-flight check submission shape.
1012
+
1013
+ Validates the submission JSON against the playbook's expected indicators /
1014
+ preconditions / artifacts WITHOUT executing detect/analyze/validate/close.
1015
+ Lets the AI iterate on its evidence before going through phases 4-7.
1016
+
1017
+ Args / flags:
1018
+ <playbook> Playbook id. Required.
1019
+ <evidence-file> Submission JSON path. Required.
1020
+ --pretty Indented JSON output.
1021
+
1022
+ Output categories: ok, missing_required, missing_required_artifact,
1023
+ unknown_keys, type_mismatch, suggestions.`,
1024
+ "verify-attestation": `verify-attestation <session-id> — alias for \`attest verify\`.
1025
+
1026
+ See \`exceptd attest --help\` for the full attest verb. This alias matches
1027
+ the historical verify-attestation entry-point name used by some downstream
1028
+ consumers.
1029
+
1030
+ Flags: --pretty.`,
1031
+ "run-all": `run-all — alias for \`run --all\`.
1032
+
1033
+ Identical exit-code and output contract as \`run --all\`. Maintained for
1034
+ operators who script the verb form rather than the flag.
1035
+
1036
+ See \`exceptd run --help\` for the full flag list.`,
929
1037
  };
930
1038
  process.stdout.write((cmds[verb] || `${verb} — no per-verb help available; see \`exceptd help\` for the full list.`) + "\n");
931
1039
  }
@@ -1562,13 +1670,20 @@ function cmdRun(runner, args, runOpts, pretty) {
1562
1670
 
1563
1671
  emit(result, pretty);
1564
1672
 
1673
+ // v0.12.8: use process.exitCode + return instead of process.exit() so
1674
+ // buffered async stdout (which `emit` writes to) is allowed to drain
1675
+ // before the event loop ends. v0.11.10 (#100) is the canonical class:
1676
+ // process.exit(N) immediately after a stdout write can truncate output
1677
+ // under piped consumers (CI runners, jq, test harnesses).
1565
1678
  if (classification === "detected") {
1566
1679
  process.stderr.write(`[exceptd run --ci] FAIL: classification=detected rwep=${adjusted} threshold=${threshold}\n`);
1567
- process.exit(2);
1680
+ process.exitCode = 2;
1681
+ return;
1568
1682
  }
1569
1683
  if (classification === "inconclusive" && escalate) {
1570
1684
  process.stderr.write(`[exceptd run --ci] FAIL: classification=inconclusive AND rwep=${adjusted} >= threshold=${threshold}\n`);
1571
- process.exit(2);
1685
+ process.exitCode = 2;
1686
+ return;
1572
1687
  }
1573
1688
  if (classification === "inconclusive") {
1574
1689
  process.stderr.write(`[exceptd run --ci] PASS+WARN: classification=inconclusive rwep=${adjusted} < threshold=${threshold} (visibility gap)\n`);
@@ -1798,9 +1913,10 @@ function cmdRunMulti(runner, ids, args, runOpts, pretty, meta) {
1798
1913
  // v0.11.9 (#100): cmdRunMulti exits non-zero when any individual run
1799
1914
  // returned ok:false. Pre-0.11.9 the aggregate result had {ok:false} in
1800
1915
  // the body but exit code stayed 0 — CI gates couldn't distinguish "ran
1801
- // clean" from "blocked." Now matches cmdRun's single-playbook contract.
1916
+ // clean" from "blocked." v0.12.8: use exitCode (not process.exit()) so
1917
+ // the aggregate JSON emitted above is allowed to fully drain.
1802
1918
  const anyBlocked = results.some(r => r.ok === false);
1803
- if (anyBlocked) process.exit(1);
1919
+ if (anyBlocked) { process.exitCode = 1; return; }
1804
1920
  }
1805
1921
 
1806
1922
  function cmdIngest(runner, args, runOpts, pretty) {
@@ -1835,28 +1951,38 @@ function cmdIngest(runner, args, runOpts, pretty) {
1835
1951
 
1836
1952
  const result = runner.run(playbookId, directiveId, cleanedSubmission, runOpts);
1837
1953
 
1954
+ // v0.12.8: route ingest's attestation persistence through persistAttestation
1955
+ // — the same path cmdRun + cmdRunMulti use — so the session-id collision
1956
+ // refusal AND the Ed25519 sidecar signing both apply. Pre-v0.12.8 ingest
1957
+ // had its own inline writeFileSync with neither check, meaning two ingest
1958
+ // calls with the same session-id silently clobbered the audit trail and no
1959
+ // .sig sidecar was written.
1838
1960
  if (result && result.ok && result.session_id) {
1839
- try {
1840
- const dir = path.join(resolveAttestationRoot(runOpts), result.session_id);
1841
- fs.mkdirSync(dir, { recursive: true });
1842
- fs.writeFileSync(
1843
- path.join(dir, "attestation.json"),
1844
- JSON.stringify({
1845
- session_id: result.session_id,
1846
- playbook_id: result.playbook_id,
1847
- directive_id: result.directive_id,
1848
- evidence_hash: result.evidence_hash,
1849
- submission: cleanedSubmission,
1850
- run_opts: { airGap: runOpts.airGap, forceStale: runOpts.forceStale, mode: runOpts.mode },
1851
- captured_at: new Date().toISOString(),
1852
- }, null, 2)
1853
- );
1854
- } catch { /* non-fatal */ }
1961
+ const persisted = persistAttestation({
1962
+ sessionId: result.session_id,
1963
+ playbookId: result.playbook_id,
1964
+ directiveId: result.directive_id,
1965
+ evidenceHash: result.evidence_hash,
1966
+ operator: runOpts.operator,
1967
+ operatorConsent: runOpts.operator_consent,
1968
+ submission: cleanedSubmission,
1969
+ runOpts,
1970
+ forceOverwrite: !!args["force-overwrite"],
1971
+ filename: "attestation.json",
1972
+ });
1973
+ if (!persisted.ok) {
1974
+ // Surface the collision; do not silently clobber.
1975
+ return emitError(persisted.error, { session_id: result.session_id, existing_path: persisted.existingPath }, pretty);
1976
+ }
1977
+ if (persisted.prior_session_id) {
1978
+ result.attestation_persist = { ok: true, prior_session_id: persisted.prior_session_id, overwrote_at: persisted.overwrote_at };
1979
+ }
1855
1980
  }
1856
1981
 
1857
1982
  if (result && result.ok === false) {
1858
1983
  process.stderr.write((pretty ? JSON.stringify(result, null, 2) : JSON.stringify(result)) + "\n");
1859
- process.exit(1);
1984
+ process.exitCode = 1;
1985
+ return;
1860
1986
  }
1861
1987
  emit(result, pretty);
1862
1988
  }
@@ -3196,13 +3322,22 @@ function cmdAiRun(runner, args, runOpts, pretty) {
3196
3322
  let handled = false;
3197
3323
  let buf = "";
3198
3324
 
3325
+ // v0.12.8: every writeLine() in this handler writes to stdout. Replacing
3326
+ // process.exit() with exitCode + closing stdin lets the JSONL frames
3327
+ // drain before the event loop ends. `handled` plus process.stdin.pause()
3328
+ // prevents further callbacks from re-entering the handler.
3329
+ const finish = (code) => {
3330
+ process.exitCode = code;
3331
+ try { process.stdin.pause(); } catch { /* non-fatal */ }
3332
+ };
3199
3333
  const handleLine = (line) => {
3200
3334
  if (handled) return;
3201
3335
  let parsed;
3202
3336
  try { parsed = JSON.parse(line); }
3203
3337
  catch (e) {
3338
+ handled = true;
3204
3339
  writeLine({ event: "error", reason: `invalid JSON on stdin: ${e.message}`, line_preview: line.slice(0, 120) });
3205
- process.exit(1);
3340
+ return finish(1);
3206
3341
  }
3207
3342
  if (!parsed || parsed.event !== "evidence" || !parsed.payload) {
3208
3343
  // Ignore non-evidence chatter so the host AI can interleave its own
@@ -3216,18 +3351,18 @@ function cmdAiRun(runner, args, runOpts, pretty) {
3216
3351
  result = runner.run(playbookId, directiveId, submission, runOpts);
3217
3352
  } catch (e) {
3218
3353
  writeLine({ event: "error", reason: `runner threw: ${e.message}` });
3219
- process.exit(1);
3354
+ return finish(1);
3220
3355
  }
3221
3356
  if (!result || result.ok === false) {
3222
3357
  writeLine({ event: "error", reason: result?.reason || "runner returned ok:false", result });
3223
- process.exit(1);
3358
+ return finish(1);
3224
3359
  }
3225
3360
  writeLine({ phase: "detect", ...result.phases?.detect });
3226
3361
  writeLine({ phase: "analyze", ...result.phases?.analyze });
3227
3362
  writeLine({ phase: "validate", ...result.phases?.validate });
3228
3363
  writeLine({ phase: "close", ...result.phases?.close });
3229
3364
  writeLine({ event: "done", ok: true, session_id: result.session_id, evidence_hash: result.evidence_hash });
3230
- process.exit(0);
3365
+ return finish(0);
3231
3366
  };
3232
3367
 
3233
3368
  // Handle empty/closed stdin: emit a hint then exit cleanly so AI agents
@@ -3235,7 +3370,8 @@ function cmdAiRun(runner, args, runOpts, pretty) {
3235
3370
  // a hung process.
3236
3371
  if (process.stdin.isTTY) {
3237
3372
  writeLine({ event: "error", reason: "ai-run streaming mode requires evidence on stdin; pipe {\"event\":\"evidence\",\"payload\":{...}} or use --no-stream." });
3238
- process.exit(1);
3373
+ process.exitCode = 1;
3374
+ return;
3239
3375
  }
3240
3376
 
3241
3377
  process.stdin.on("data", (chunk) => {
@@ -3270,7 +3406,8 @@ function cmdAiRun(runner, args, runOpts, pretty) {
3270
3406
  } catch { /* fall through to error */ }
3271
3407
  }
3272
3408
  writeLine({ event: "error", reason: "stdin closed without an evidence event. Pipe `{\"event\":\"evidence\",\"payload\":{...}}` for streaming mode, or pass --no-stream + --evidence <file> for single-shot." });
3273
- process.exit(1);
3409
+ process.exitCode = 1;
3410
+ return;
3274
3411
  }
3275
3412
  });
3276
3413
 
@@ -1,58 +1,58 @@
1
1
  {
2
2
  "schema_version": "1.1.0",
3
- "generated_at": "2026-05-13T04:36:48.434Z",
3
+ "generated_at": "2026-05-13T13:59:56.237Z",
4
4
  "generator": "scripts/build-indexes.js",
5
5
  "source_count": 49,
6
6
  "source_hashes": {
7
- "manifest.json": "d3272a211860b1c978ec1a3dbacbb859944a4ca5fe88a0c9ac86982dc2be1bca",
8
- "data/atlas-ttps.json": "1500b5830dab070c4252496964a8c0948e1052a656e2c7c6e1efaf0350645e13",
7
+ "manifest.json": "0c902335db71d5fc3851d661ef93e39d5e0abf987166efd916fe1f6c24db448e",
8
+ "data/atlas-ttps.json": "f3f75ff2778a0a2c7d953a21386bc4f265cb2685ce41242eee45f9e9f2a6add6",
9
9
  "data/cve-catalog.json": "a2557e66c00334f9b2b07f7d1320a27fb0f82243f2ff199c4a39bf2933be5216",
10
- "data/cwe-catalog.json": "c3367d469b4b3d31e4c56397dd7a8305a0be338ecd85afa27804c0c9ce12157b",
11
- "data/d3fend-catalog.json": "b5cd14669e2a931d0df81bb8402f3c8ac08b0d2613e595eaecd8cc4631a57587",
10
+ "data/cwe-catalog.json": "68e22967d39a9e22b82d7ac676125f829b551b2c2f3a9c564d3d942bf4ee6ecb",
11
+ "data/d3fend-catalog.json": "d219520c8d3eb61a270b25ea60f64721035e98a8d5d51d1a4e1f1140d9a586f9",
12
12
  "data/dlp-controls.json": "8ea8d907aea0a2cfd772b048a62122a322ba3284a5c36a272ad5e9d392564cb5",
13
13
  "data/exploit-availability.json": "7dad52f459c324c40aa4df7cd9157f6a19f670fdfb9d8f687d777c9d99798668",
14
- "data/framework-control-gaps.json": "25db4d0cc9e6242e1143494178393ae8eab3384672ca0d685bd55c537f028c83",
14
+ "data/framework-control-gaps.json": "8804a10bf77e987453ea76ae717153118dc5cc625f42e98f78213b08fa144f73",
15
15
  "data/global-frameworks.json": "84fd19061f052e4ccf66308a7b8d3fd38e00325e97e9e5e19e4d9b302c128957",
16
- "data/rfc-references.json": "23ffeb970af5403e9a733844dcea9b45cbae689623085f030dec826c492682e3",
16
+ "data/rfc-references.json": "583360bae01e324d752bd28a7d344b4276478381426428d683fc82b0ac19d64a",
17
17
  "data/zeroday-lessons.json": "0840eacd580d4ee5bd7dc44ccea6d52bfa95096576af0ccf67132eea05bedd55",
18
- "skills/kernel-lpe-triage/skill.md": "c00e0a77e8b7b1a1ebcb7267dd728b39ec2671d1260bf4f6a4842f10101a69b0",
19
- "skills/ai-attack-surface/skill.md": "3f5c59f1823f1552efe8a5cb32656d34d6407609ddaa1eed254c263864563453",
20
- "skills/mcp-agent-trust/skill.md": "716d0d65499f8be21e0389a06a1fcaf6abd1cd2e90f068cab54471dd67127f74",
18
+ "skills/kernel-lpe-triage/skill.md": "e8b8601cd3b66d25150bf17f2edd2ef18f10ca6d81ee62aaf874432ee5bdc4b3",
19
+ "skills/ai-attack-surface/skill.md": "30003e515a32a6314e4a72c12b8376c52e0dd85b4e36e7957c30cabbd46c8837",
20
+ "skills/mcp-agent-trust/skill.md": "cd48cbf5a9c9795db525acea970db0c171cf9da4211bd07971b5132a1cde485c",
21
21
  "skills/framework-gap-analysis/skill.md": "86c86761b91d04bcd1ec684fb3d65cf5c2881fde59b03d33fa59baddbbf64d31",
22
22
  "skills/compliance-theater/skill.md": "dda149e69fcd92d913f3f6be4aa1aba8fe85a2b408b88c052c71174b2e0e918c",
23
23
  "skills/exploit-scoring/skill.md": "993dbd4417018e5d20edb31ff2296b92b65fff42d2acde722c05e0be7994ddbe",
24
- "skills/rag-pipeline-security/skill.md": "6274bbac1fbd164123f4d57a49c5cc7429846b7452ea476095e9dc846fdc2c42",
25
- "skills/ai-c2-detection/skill.md": "afe4258fa03e3fd81ca4bb7b348cb483585eb129ebae811457810b5290080793",
24
+ "skills/rag-pipeline-security/skill.md": "cb31137b62c34905b633a10e4a9bcc6dcccc7448f254e63d7203ee7f7b469a03",
25
+ "skills/ai-c2-detection/skill.md": "ff5fc781d8768a81b980566d1b8b56299cdbb61a56ff24b30b459c7c0ee95464",
26
26
  "skills/policy-exception-gen/skill.md": "6a18b1ecd342dd792e03fcadaed3aa846192f2408c21c79d98eadd431e1619e1",
27
27
  "skills/threat-model-currency/skill.md": "afa24a1d04202a384374598ea2d924cdaa52e264b9552bae1ace88fd39d6c0e8",
28
28
  "skills/global-grc/skill.md": "a9f4477368e260609793b77275e65e255b5c8067b7ae777047a70f3edb373e50",
29
29
  "skills/zeroday-gap-learn/skill.md": "b101815b1c55e95706d72d31eb88153a92f41a748a86e111ad1ac06b9c676548",
30
30
  "skills/pqc-first/skill.md": "5b4300d71890c16b1de31d380859babaa3631729cedb0c0a397a1ff097524773",
31
- "skills/skill-update-loop/skill.md": "c8bfea03c60403fb26e3ab7e07406660ef148bece9e12f9149b5171033cf5e22",
32
- "skills/security-maturity-tiers/skill.md": "931d6144048308124930e8036d8e74931ca176f7315e110d33fb30880d2f5367",
31
+ "skills/skill-update-loop/skill.md": "f48c40e0f2a893d5877b73159218d007b0f5f9295e591cbc3323745899fb3481",
32
+ "skills/security-maturity-tiers/skill.md": "b4c8eb22d705d36ff863a431df7406096d294dda3c8c3037aa7ad025b47ddb5a",
33
33
  "skills/researcher/skill.md": "40de9c281ea82e92b21856b5dde15609f187d8cddc7e4116886ac0fff9d0e269",
34
- "skills/attack-surface-pentest/skill.md": "f639b6d9c19def5908eddbbb79f0514e168e74661c0894b737d7c76cbb550841",
34
+ "skills/attack-surface-pentest/skill.md": "40f5a6a6c80e6084a1c09fb0085d0083f4970385bf76098015e57fc17ad7b326",
35
35
  "skills/fuzz-testing-strategy/skill.md": "83b1929a0d1e09a58908b91125ebc91ff14323ab9acc9bab6c4b04903b69b837",
36
- "skills/dlp-gap-analysis/skill.md": "041c4c6a5299057383b1d6bd4328c1ef578f8c5c6bade8750d339c7b51020027",
37
- "skills/supply-chain-integrity/skill.md": "94527929c150bf9bc7a5a61a596373d49a88ae9114adf841b2d3771e25fb8d51",
38
- "skills/defensive-countermeasure-mapping/skill.md": "634f0805597a0ab417248a7413eed39b08afbc820e7c6bd257eebaa663d8990d",
39
- "skills/identity-assurance/skill.md": "e8f3958ef8dd89f9276f2a62a0a1b418a206a3312bb8ff228729c8f358603dc7",
40
- "skills/ot-ics-security/skill.md": "7c6eb389e7ace5b2c6e092f8dfcf4795ce1b0aefaa2738c6e383cb0fef4d6287",
41
- "skills/coordinated-vuln-disclosure/skill.md": "22ba9ee01252274b1e4aa1238468415c6f564eca319c601de588fbcdd1bea3bb",
42
- "skills/threat-modeling-methodology/skill.md": "9e1ee084a56f837074a41b7a7929b1deb5619bb483485aa066b0c26990fe70db",
43
- "skills/webapp-security/skill.md": "10a17ab8d3f0e9b1107f7bed5ff2881f59234592b57f2a52c8c397d711604ffb",
44
- "skills/ai-risk-management/skill.md": "6062be4e748606ca7536bba3d87e25716795d5690a0063f188325e8e68291cb6",
45
- "skills/sector-healthcare/skill.md": "01dd58ed20b3f97dc240e1b77a522f780bd9428294ac9ac78d51817150b55476",
46
- "skills/sector-financial/skill.md": "52bdf30cece82381ea8a4023838aa61a2b9026f315a1356aabb638e49bf7b6d9",
47
- "skills/sector-federal-government/skill.md": "e1443a3f788050fd5d63d001a3aafbd3244280399ccdec595d7807de547614d4",
48
- "skills/sector-energy/skill.md": "068996fa85cc9d8d7f890b185a38619602cb3bab89704d3bfc85c99cbddaafb8",
49
- "skills/api-security/skill.md": "131de2913341f794585091b72522b0e0b8d7dd42eca4faf8ea7315d27b5a5c6f",
50
- "skills/cloud-security/skill.md": "26e533f5fa4876cb611cfa026fb7e6417927dd4c2e04f50e42fc08016c40274b",
51
- "skills/container-runtime-security/skill.md": "7c62132c189edfe0e803c1cc2a688cef7b6ddd2d3be8c5d74a807293f14e0790",
52
- "skills/mlops-security/skill.md": "78bb564f841f2c60ea48790ba686ba1e3f628afd402c96847177cc7e05fba4de",
53
- "skills/incident-response-playbook/skill.md": "ede731be2bd673d65a8b7509ca3e2eb9af800186780a99c0369e15b2459d7cb6",
54
- "skills/email-security-anti-phishing/skill.md": "9dfc1ca36f3059bb8f1cbc566d1358d1c797bb8f51d7bd62a70df8505563ab23",
55
- "skills/age-gates-child-safety/skill.md": "f477320c9727986a44f38dc470e61a2c50bf9eef0a6a4c4ab1f14462dfa94f73"
36
+ "skills/dlp-gap-analysis/skill.md": "61149c692de109d5cfd00cada60478539f28374380b5ce17017603d71967ab58",
37
+ "skills/supply-chain-integrity/skill.md": "961eb734df9965fa726720ac9f849bdcdc32108625d1d589602005967b836ea8",
38
+ "skills/defensive-countermeasure-mapping/skill.md": "e62c71ba3be2b4d0f7dfa529fec007cba6bee3013f76b93756e3e6310f2d22ab",
39
+ "skills/identity-assurance/skill.md": "a4aff24b0d0f4684d144f85cbc74c8a9a5711a7ec9c6d473f677f053dc1c658c",
40
+ "skills/ot-ics-security/skill.md": "500a002b662217393243d093efa639cdf30ca76d1869d6c1896425492c5d652e",
41
+ "skills/coordinated-vuln-disclosure/skill.md": "c96fd2254abf8a29819f8175da85094bea1afe589fecc92abcf1289b30895030",
42
+ "skills/threat-modeling-methodology/skill.md": "eb03a6c12c637c38917fecd97007459dfe99cbab5dfae696a736f08db13c124c",
43
+ "skills/webapp-security/skill.md": "009d9050e3c27f789efbc4c0dba4245b66d49182b503736be6a344591ba93f54",
44
+ "skills/ai-risk-management/skill.md": "1bbdba6b46efba8c88f8e7e1930777d39a65709ea434b6a53eed01814fa9fdad",
45
+ "skills/sector-healthcare/skill.md": "43608ca43eefc3a9238f6c6b0c7993e519420ffab5a18d96e17310f44ac6225a",
46
+ "skills/sector-financial/skill.md": "d7b538cd71a8384c9e19a86e7971049f2c1f651677e4ab9b5a1caf9526b178da",
47
+ "skills/sector-federal-government/skill.md": "0d18ede4d0c04975ea22bfa53b0f6d62eeb70861e16a27d239d25928fa3ff21f",
48
+ "skills/sector-energy/skill.md": "07ca8b582b3a94657006395ce0ef15ecb2030f676f119900b4fdb9b213f04200",
49
+ "skills/api-security/skill.md": "99af9882f57e884b3f66f1c17a4bc6ee24ed6531f0e28b3bdeccd5d77429ffa6",
50
+ "skills/cloud-security/skill.md": "18fc0f16689f3560023c9d919bec03070d3c2198dc186d1b7ca9cfe35fbfa108",
51
+ "skills/container-runtime-security/skill.md": "f481878aa40c42662424d32b320fc825e2550b7874224765e2150a97f0afeafb",
52
+ "skills/mlops-security/skill.md": "c9fb9281191b2684424f96b3d4447fe40907f633b0506e22100d909141f497be",
53
+ "skills/incident-response-playbook/skill.md": "27202d956fcc06c0cef7ad1ca6f352e2cdf06189516e22f796704a44c2ab2734",
54
+ "skills/email-security-anti-phishing/skill.md": "90e15fb89a36ac704cb092801130351a5c33bb7154bd023a347309c1a6a4f164",
55
+ "skills/age-gates-child-safety/skill.md": "c741d7dca9da0abb09bdebb8a02e803ce4ae9fb9a6904fb8df3ec19cae83917d"
56
56
  },
57
57
  "skill_count": 38,
58
58
  "catalog_count": 10,
@@ -68,12 +68,12 @@
68
68
  },
69
69
  "trigger_table_entries": 453,
70
70
  "chains_cve_entries": 6,
71
- "chains_cwe_entries": 34,
71
+ "chains_cwe_entries": 51,
72
72
  "jurisdictions_indexed": 29,
73
73
  "handoff_dag_nodes": 38,
74
74
  "summary_cards": 38,
75
75
  "section_offsets_skills": 38,
76
- "token_budget_total_approx": 334832,
76
+ "token_budget_total_approx": 337096,
77
77
  "recipes": 8,
78
78
  "jurisdiction_clocks": 29,
79
79
  "did_ladders": 8,