@blamejs/exceptd-skills 0.13.59 → 0.13.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.62 — 2026-05-24
4
+
5
+ Threat-framework version pins are now consistent across the full surface. The remaining skills and the source registry cite MITRE ATT&CK v19.0 (April 2026); `attack-surface-pentest` and `skill-update-loop` still described the superseded v17 matrix, and `sources/index.json` pointed callers at v17 / 2025-06-25. The same registry's ATLAS pointer is corrected to v5.6.0 (May 2026) — it had drifted to v5.1.0 while every other surface moved on. A new guard refuses any operator-facing reference to an ATT&CK version older than the catalog pin, while permitting forward-looking references so forward-watch entries naming the next release cycle stay intact.
6
+
7
+ ### Bugs
8
+
9
+ - **`attack-surface-pentest` and `skill-update-loop` cited ATT&CK v17** in their TTP-mapping tables and source-tracking rows while the catalog pin (`data/attack-techniques.json._meta.attack_version`) is v19.0. The version operators read in the skill body now matches the version the engine resolves against.
10
+ - **`sources/index.json` pinned ATT&CK at v17 / 2025-06-25 and ATLAS at v5.1.0 / 2025-11-01** — the machine-readable "current version" pointers consumers read to learn which framework revision the catalog tracks. Both now match the catalog: ATT&CK v19.0 / 2026-04-28, ATLAS v5.6.0 / 2026-05-08, with the ATLAS update cadence corrected to monthly.
11
+
12
+ ### Internal
13
+
14
+ - Added an ATT&CK-version drift guard mirroring the existing ATLAS guard. It is stale-only: a reference older than the pinned version fails the suite; an equal-or-newer reference (how forward-watch records the next release) passes. The source-registry version pointers are asserted against the catalog pins so they cannot silently diverge again.
15
+
16
+ ## 0.13.61 — 2026-05-22
17
+
18
+ Documentation and skill-content drift fixes. `package.json` description, SBOM metadata, and the operator-queryable catalog summary now report the correct 35-jurisdiction count. Eight skills correct their MITRE ATLAS release date (May 2026, not February 2026); three skills bump their ATT&CK pin to v19.0 to match `data/attack-techniques.json._meta.attack_version` and the AGENTS.md Hard Rule #12 pin. `refresh --check-advisories` help text now enumerates all 15 advisory feeds the runtime polls. The agents/ directory roster drops a broken link to a non-existent `framework-analyst.md` and folds its responsibility into `threat-researcher`.
19
+
20
+ ### Bugs
21
+
22
+ - **`package.json.description` and `sbom.cdx.json` reported "34 jurisdictions"** while every other surface (README badge, README body, ARCHITECTURE.md, CONTEXT.md) reported 35 and `data/global-frameworks.json` actually ships 35. The npm registry blurb — the first discovery-path operators see — was wrong by one. Bumped to 35 across both, plus `scripts/builders/catalog-summaries.js` and the regenerated `data/_indexes/catalog-summaries.json` which downstream AI consumers query for catalog introspection.
23
+ - **Eight skills described MITRE ATLAS v5.6.0 as released "February 2026" (or `2026-02-06`)** when the actual release date is `2026-05-08` (May 2026), as pinned in AGENTS.md Hard Rule #12 and `data/atlas-ttps.json._meta.atlas_release_date`. Audit traceability — "which TTP catalog were we using on May 1?" — requires the date to be consistent across the shipped surface. Fixed in compliance-theater, framework-gap-analysis, incident-response-playbook, policy-exception-gen, mlops-security (×2), rag-pipeline-security, ransomware-response, and skill-update-loop (×2).
24
+ - **Three skills referenced ATT&CK v17 (2025-06-25) and AGENTS.md "rule #8"** — both stale. Hard Rule #8 is compliance-theater detection, not version pinning; the version-pinning rule is #12. The pinned ATT&CK version per AGENTS.md and `data/attack-techniques.json._meta.attack_version` is v19.0 (April 2026), which split Defense Evasion into Stealth (TA0005) and Defense Impairment (TA0112). Skills now cite the correct rule number and the current pinned version. Affects incident-response-playbook and ransomware-response.
25
+ - **`refresh --check-advisories` help text enumerated 12 venues** while the prose around it (and the runtime in `lib/source-advisories.js`) polls 15. The three omissions — BleepingComputer security, The Hacker News, and the Nightmare-Eclipse GitHub tracker — are now listed inline so the count and the enumeration agree.
26
+ - **`agents/README.md` listed a `framework-analyst.md` role that has no file on disk** — the roster, workflow diagram, and parallelization section all referenced a fifth agent that ships as a 404. The threat-researcher role already covers framework amendments; its description and trigger list now reflect that, and the broken row + diagram node are removed.
27
+
28
+ ## 0.13.60 — 2026-05-22
29
+
30
+ Final tranche of audit cycle 3 polish. `doctor` surfaces the local version; `--collectors` distinguishes policy-skipped from actually-missing collectors; `ask` confidence penalizes ties.
31
+
32
+ ### Features
33
+
34
+ - **`doctor` surfaces `local_version`** at the top of the JSON envelope + in the text header. Operators see "which version am I running?" alongside "is my install healthy?" without invoking `exceptd version` separately. Opt-in `--registry-check` augments with the published comparison; `local_version` alone is offline-clean.
35
+ - **`doctor --collectors` adds `unexplained_missing_collectors`** — the set difference of `without_collector` and `policy_skips`. Previously these were identical-by-coincidence; a future regression that lost an active collector or a policy-skipped playbook that gained one would have gone unnoticed. The new field surfaces the operator-actionable gaps directly.
36
+ - **`ask` confidence is penalized by tie spread.** A 5-way tie at the top score no longer reports the same confidence as a single clear winner. `confidence_factors` surfaces `base` (raw score / token count) + `tie_count` so consumers can introspect the math. Tied scores also break alphabetically only as a last resort — direct id-match between the question and a playbook id now outranks alphabetical accident.
37
+
3
38
  ## 0.13.59 — 2026-05-22
4
39
 
5
40
  Air-gap mode honored by `--upstream-check` and the `collect` envelope. `doctor` subchecks surface freshness timestamps + walk-cap markers. `--collectors` text matches its JSON.
package/README.md CHANGED
@@ -366,8 +366,10 @@ exceptd refresh Refresh upstream catalogs + indexes.
366
366
  ZDI, kernel.org commits, oss-security
367
367
  mailing list, JFrog SecOps, CISA current
368
368
  advisories, Microsoft Security Blog,
369
- Sysdig, Trail of Bits, Embrace the Red)
370
- for CVE IDs disclosed at T+0 to T+1 —
369
+ Sysdig, Trail of Bits, Embrace the Red,
370
+ BleepingComputer, The Hacker News,
371
+ Nightmare-Eclipse GitHub tracker) for
372
+ CVE IDs disclosed at T+0 to T+1 —
371
373
  days ahead of NVD enrichment.
372
374
  Report-only: emits structured diffs[]
373
375
  with {cve_id, sources[], advisory_urls[],
package/agents/README.md CHANGED
@@ -8,9 +8,8 @@ Multi-agent coordination for exceptd Security. Each agent file defines a special
8
8
 
9
9
  | Agent | Role | Triggers |
10
10
  |---|---|---|
11
- | [threat-researcher](threat-researcher.md) | Research and validate new CVEs, threat campaigns, and ATLAS TTPs | New CVE published, ATLAS update, CISA KEV addition |
12
- | [framework-analyst](framework-analyst.md) | Analyze framework updates and gap changes | Framework amendment published |
13
- | [skill-updater](skill-updater.md) | Apply validated intelligence to update skill files | Threat researcher or framework analyst output |
11
+ | [threat-researcher](threat-researcher.md) | Research and validate new CVEs, threat campaigns, ATLAS TTPs, and framework updates | New CVE published, ATLAS update, CISA KEV addition, framework amendment |
12
+ | [skill-updater](skill-updater.md) | Apply validated intelligence to update skill files | Threat researcher output |
14
13
  | [source-validator](source-validator.md) | Cross-check data against primary sources | Before any data enters cve-catalog.json or atlas-ttps.json |
15
14
  | [report-generator](report-generator.md) | Generate structured reports from skill outputs | User invokes a reporting workflow |
16
15
 
@@ -21,8 +20,8 @@ Multi-agent coordination for exceptd Security. Each agent file defines a special
21
20
  ```
22
21
  External trigger (new CVE, ATLAS update, framework change)
23
22
 
24
- [threat-researcher] or [framework-analyst]
25
- — researches the trigger
23
+ [threat-researcher]
24
+ — researches the trigger (CVE, ATLAS update, or framework amendment)
26
25
  — identifies affected skills
27
26
  — produces a validated intelligence package
28
27
 
@@ -48,8 +47,7 @@ External trigger (new CVE, ATLAS update, framework change)
48
47
  These agents can run in parallel when their inputs are independent:
49
48
 
50
49
  **Parallel-safe:**
51
- - Multiple threat-researcher instances on different CVEs
52
- - framework-analyst + threat-researcher on unrelated topics
50
+ - Multiple threat-researcher instances on different CVEs or framework amendments
53
51
  - Multiple source-validator instances on different data items
54
52
 
55
53
  **Must be sequential:**
package/bin/exceptd.js CHANGED
@@ -6586,16 +6586,51 @@ function cmdDoctor(runner, args, runOpts, pretty) {
6586
6586
  }
6587
6587
  }
6588
6588
  const ok = load_errors.length === 0;
6589
+ // Audit 3 B.6: pre-fix `without_collector` was just "playbooks
6590
+ // missing a collector file" — which happened to equal POLICY_SKIPS
6591
+ // exactly because every policy-skipped playbook also has no
6592
+ // collector. That coincidence isn't an invariant: a future
6593
+ // playbook could lose its collector by accident OR a policy-skipped
6594
+ // playbook could gain a collector intentionally. Distinguish the
6595
+ // two: `without_collector` is now playbooks-missing-a-collector
6596
+ // that are NOT in the policy-skip allowlist — i.e. actual gaps
6597
+ // that need attention. The set-difference is what operators
6598
+ // should remediate.
6599
+ // Pre-fix `without_collector` was just "playbooks missing a
6600
+ // collector file" — which happened to equal POLICY_SKIPS exactly
6601
+ // because every policy-skipped playbook also has no collector.
6602
+ // That coincidence isn't an invariant: a future playbook could
6603
+ // lose its collector by accident OR a policy-skipped playbook
6604
+ // could gain one. The new `unexplained_missing_collectors`
6605
+ // field surfaces the operator-actionable set difference:
6606
+ // playbooks missing a collector that are NOT in the policy
6607
+ // allowlist. Existing `without_collector` retained for
6608
+ // back-compat.
6609
+ const policySkipSet = new Set(POLICY_SKIPS);
6610
+ const unexplained_missing_collectors = without_collector.filter(p => !policySkipSet.has(p));
6611
+ // Audit-3 codex P1 follow-up: when an unexplained missing collector
6612
+ // appears (a playbook that SHOULD have a collector but doesn't,
6613
+ // i.e. NOT in the policy-skip allowlist), the check fails. Without
6614
+ // this, automation and CI health checks would miss the exact
6615
+ // regression class that unexplained_missing_collectors exists to
6616
+ // surface. Load errors still fail at "error" severity; unexplained
6617
+ // missings fail at "warn" (they're a build-time gap, not a
6618
+ // runtime crash).
6619
+ const collectorOk = ok && unexplained_missing_collectors.length === 0;
6620
+ const collectorSeverity = load_errors.length > 0 ? "error"
6621
+ : unexplained_missing_collectors.length > 0 ? "warn"
6622
+ : "info";
6589
6623
  checks.collectors = {
6590
- ok,
6591
- severity: ok ? "info" : "error",
6624
+ ok: collectorOk,
6625
+ severity: collectorSeverity,
6592
6626
  total_playbooks: playbookFiles.length,
6593
6627
  with_collector,
6594
6628
  without_collector,
6629
+ unexplained_missing_collectors,
6595
6630
  load_errors,
6596
6631
  policy_skips: POLICY_SKIPS.sort(),
6597
6632
  };
6598
- if (!ok) issues.push("collectors");
6633
+ if (!collectorOk) issues.push("collectors");
6599
6634
  } catch (e) {
6600
6635
  checks.collectors = { ok: false, severity: "error", error: e.message };
6601
6636
  issues.push("collectors");
@@ -6615,8 +6650,18 @@ function cmdDoctor(runner, args, runOpts, pretty) {
6615
6650
  const { bucketChecks } = require(path.join(PKG_ROOT, "lib", "doctor-bucketing.js"));
6616
6651
  const { warnList, errorList } = bucketChecks(checks);
6617
6652
  const allGreen = errorList.length === 0 && warnList.length === 0;
6653
+ // Audit 3 B.11: surface the local version on the default doctor output
6654
+ // so operators answer both "is my install healthy?" AND "which version
6655
+ // am I running?" without having to invoke `exceptd version` separately.
6656
+ // The opt-in --registry-check augments this with the published comparison;
6657
+ // local_version alone is offline-clean.
6658
+ let localVersion = null;
6659
+ try {
6660
+ localVersion = require(path.join(PKG_ROOT, "package.json")).version || null;
6661
+ } catch { /* package.json unreadable — fall through */ }
6618
6662
  const out = {
6619
6663
  verb: "doctor",
6664
+ local_version: localVersion,
6620
6665
  checks,
6621
6666
  summary: {
6622
6667
  all_green: allGreen,
@@ -6727,7 +6772,7 @@ function cmdDoctor(runner, args, runOpts, pretty) {
6727
6772
 
6728
6773
  // Default: human checklist. v0.11.0 redesign #5.
6729
6774
  const lines = [];
6730
- lines.push("exceptd doctor");
6775
+ lines.push(`exceptd doctor${localVersion ? ` (v${localVersion})` : ""}`);
6731
6776
  function mark(c, render) {
6732
6777
  if (!c) return;
6733
6778
  // Four states: ok / warn / error / skipped. `skipped` is informational
@@ -7546,7 +7591,20 @@ function cmdAsk(runner, args, runOpts, pretty) {
7546
7591
  if (tokens.some(t => (pb._meta?.id || id) === t)) score += 3;
7547
7592
  scored.push({ id: pb._meta?.id || id, score });
7548
7593
  }
7549
- scored.sort((a, b) => b.score - a.score);
7594
+ // Audit 3 C.6: when scores tie, fall back to a deterministic but more
7595
+ // useful order than alphabetical playbook-id (which made the first-5
7596
+ // playbooks dominate every vague query). Secondary sort favors
7597
+ // playbooks whose id is referenced directly in the question (e.g.
7598
+ // "secrets" matching playbook id "secrets" outranks an alphabetical
7599
+ // accident). Tertiary is the original stable order.
7600
+ scored.forEach((s, i) => { s._origIdx = i; });
7601
+ scored.sort((a, b) => {
7602
+ if (b.score !== a.score) return b.score - a.score;
7603
+ const aIdMatch = tokens.includes(a.id) ? 1 : 0;
7604
+ const bIdMatch = tokens.includes(b.id) ? 1 : 0;
7605
+ if (aIdMatch !== bIdMatch) return bIdMatch - aIdMatch;
7606
+ return a._origIdx - b._origIdx;
7607
+ });
7550
7608
  const top = scored.filter(s => s.score > 0).slice(0, 5);
7551
7609
 
7552
7610
  // v0.11.2: default human-readable; --json for machine.
@@ -7575,11 +7633,22 @@ function cmdAsk(runner, args, runOpts, pretty) {
7575
7633
  t.collector_available = fs.existsSync(collectorPath);
7576
7634
  }
7577
7635
 
7636
+ // Audit 3 C.7: penalize confidence by the tie spread at the top so a
7637
+ // 5-way tie at score 3 doesn't claim the same confidence as a single
7638
+ // clear winner at score 3. tieCount counts how many playbooks share
7639
+ // the top score (1 = clean winner; >1 = tie). Confidence divided
7640
+ // accordingly: a 5-way tie reports ~0.2x the base, a clean winner
7641
+ // reports the full base.
7642
+ const topScore = top[0].score;
7643
+ const tieCount = scored.filter(s => s.score === topScore).length;
7644
+ const baseConfidence = Math.min(1, topScore / Math.max(2, tokens.length));
7645
+ const tiePenalty = tieCount > 1 ? 1 / tieCount : 1;
7578
7646
  const result = {
7579
7647
  verb: "ask",
7580
7648
  question,
7581
7649
  routed_to: top.map(t => t.id),
7582
- confidence: Math.min(1, top[0].score / Math.max(2, tokens.length)),
7650
+ confidence: Math.round(baseConfidence * tiePenalty * 100) / 100,
7651
+ confidence_factors: { base: Math.round(baseConfidence * 100) / 100, tie_count: tieCount },
7583
7652
  next_step: `exceptd run ${top[0].id} # or: exceptd brief ${top[0].id} to learn first`,
7584
7653
  full_match_list: top,
7585
7654
  };
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "schema_version": "1.1.0",
3
- "generated_at": "2026-05-22T23:28:32.508Z",
3
+ "generated_at": "2026-05-24T14:51:18.851Z",
4
4
  "generator": "scripts/build-indexes.js",
5
5
  "source_count": 54,
6
6
  "source_hashes": {
7
- "manifest.json": "020990fd6a13ea3a2a0273e80d0607c1cf0fd8887f03bb48294d2568a22d2789",
7
+ "manifest.json": "a5c737f12027f2dbea6de6ea9e540a81a075ba49cf0d4d72bdb9b247732e3907",
8
8
  "data/atlas-ttps.json": "d296c1d3e71807c9279b731f047e57796e85137f186586743a8cdad214b408f9",
9
9
  "data/attack-techniques.json": "49b6010b317edd219def135171ea8f3b1bbf1e00e9c5a08bf7237215ff54e2c3",
10
10
  "data/cve-catalog.json": "a09c83af3f9679a7ea73935726a1ff9de2cab94b4ab6321fc017fc147747d7c3",
@@ -19,20 +19,20 @@
19
19
  "skills/kernel-lpe-triage/skill.md": "08b3e9815ba481c57c80f5fc0ccbf5bb7cbb41f570c235ba6ff9596b8c07354d",
20
20
  "skills/ai-attack-surface/skill.md": "6ff82cd5e805a29b694a71ffbeba22e78966249da921706f3256fa4319e402fc",
21
21
  "skills/mcp-agent-trust/skill.md": "bf3ded40e84443400c9bec8634e0d6a14c9633e569d8c2e26f9d5881f8e78dff",
22
- "skills/framework-gap-analysis/skill.md": "82acc8fc68ee5cc7aaddff1632a63524663981d4b9ce064f8543d1cfbba1b770",
23
- "skills/compliance-theater/skill.md": "a664e202d4fdcd28eb3216983d6b982b288ce8e553461fa79468c6a1744b83ee",
22
+ "skills/framework-gap-analysis/skill.md": "17249909697a9c61b71f6885a1f4888ab1e727909ddb487ed82aeef535884a4f",
23
+ "skills/compliance-theater/skill.md": "d656444bb1987f43ae61374f210977d0c1f247f54d7318fdd639dd0cfdbef392",
24
24
  "skills/exploit-scoring/skill.md": "f55e9aa4985ebad8a2a12092c937deb6939a639dc1e16e2214ecfa1c9b9402c4",
25
- "skills/rag-pipeline-security/skill.md": "785dac24078f4f3d798f04607aa13d2d902d027fb5ea95d1074240c4762b2dff",
25
+ "skills/rag-pipeline-security/skill.md": "d3ad18562a6083fb773347e24b6fcda2adcb68b4269e29df53b5afeb113cf7b0",
26
26
  "skills/ai-c2-detection/skill.md": "524474483bdfa9614cf31276f16c0ec365a364e61e9ca6047c08621751539671",
27
- "skills/policy-exception-gen/skill.md": "76c8f4dadf470103a467f40b01870585d8769c1af2bc15956e1d8b0b424626ae",
27
+ "skills/policy-exception-gen/skill.md": "238074319b57399c75d76439ef1ff67153b5a3207adf1556f3ca1e68cfe7cfaa",
28
28
  "skills/threat-model-currency/skill.md": "4295c0efe31dcbec1a7bc96b8ce05d41414d918cbfc7fb7dffb2be7e4d873ae3",
29
29
  "skills/global-grc/skill.md": "57ca729034e9d33c527d869c1c4aa82fe37e496878a3cbcd9e5043cb62b7105d",
30
30
  "skills/zeroday-gap-learn/skill.md": "d8872a4f5e5e927ae087e8319996ec3b9e010aa23fca32248c0909051032db48",
31
- "skills/pqc-first/skill.md": "07b38278b60d2437603a541c1ee954999abfe3a192f94b43cd384023738a0c1f",
32
- "skills/skill-update-loop/skill.md": "358a0ac73bc7f211def7e2ad0d3eda147f847ded3a3f1dd27afdd360226e8add",
31
+ "skills/pqc-first/skill.md": "3b41b59eb4e8480b691ff17185f42b9fbfd7665e369fc210feba496688cc77aa",
32
+ "skills/skill-update-loop/skill.md": "f7cd18df293b90c0d2afb6ba8b87664419becea6b63221f03efaf09c69586025",
33
33
  "skills/security-maturity-tiers/skill.md": "2e46c9332a5a6190d4605ba7bc653410659be19fab50c78c0a6732f84ebdb300",
34
34
  "skills/researcher/skill.md": "959aeba706eea43a69136561968d7942dcd981d0a6c3da7db47673c51943b6df",
35
- "skills/attack-surface-pentest/skill.md": "7609380c53bfc829b28a4478457a887aadcf31ddbade2d6ecf56fc5f845a0f72",
35
+ "skills/attack-surface-pentest/skill.md": "d6ea35136f93eb4aa75b65a5ae402353b0e2c63a83acece1606fe3f5d1ec6a8d",
36
36
  "skills/fuzz-testing-strategy/skill.md": "86e7bf537e4313b932acaba6282a4514336066a740bdbee4e7cbea2d2ef05b54",
37
37
  "skills/dlp-gap-analysis/skill.md": "b5183b5ea6fad6986500d7a04e83239a5fbf4272eaa6888b8be6420ce3d36ac5",
38
38
  "skills/supply-chain-integrity/skill.md": "90e930ef5d4cc5a54653844098d3549c3760b1a4aba5c48db1bd4eb24bea8d1b",
@@ -51,9 +51,9 @@
51
51
  "skills/api-security/skill.md": "120ed75df17db4dfc4746b9d5bd6efd33786bbf68cb840670aeed0be505866f9",
52
52
  "skills/cloud-security/skill.md": "425be2c6e3563f011d0280bf03268425bf60923ae3d02eafbf1b56d04f0b7ffe",
53
53
  "skills/container-runtime-security/skill.md": "f22bf5a305f8a33884d49d9bfb25fa2bd00c4b3d0dc490bd12f20a7721683b4a",
54
- "skills/mlops-security/skill.md": "90225bee8c6980a08a4d9601ece15337d065fd12ff52b0821a91eee63aa6950a",
55
- "skills/incident-response-playbook/skill.md": "4d1509db64c59a8985bef7f53dfe6be54887e2989b39ed51f19eacc761750877",
56
- "skills/ransomware-response/skill.md": "1455eeecbb18962447af80fe3d49aead15ebe7b45c206d8f4bd7d0c202b9681a",
54
+ "skills/mlops-security/skill.md": "498549ddc9d870cb8d6a28a4d79b8d7058d5eed832d7c266c281084f4371ce46",
55
+ "skills/incident-response-playbook/skill.md": "9c219de36c7d702dff8504a25e2f1b07459716ea2ed02f49d751f91dbeca1b01",
56
+ "skills/ransomware-response/skill.md": "471b714c42717d43f81b2b582cd8e89ca8d3140de2ddc06cce15f012a0e19be1",
57
57
  "skills/email-security-anti-phishing/skill.md": "250f266908f51f99a4cb3aec0d5dacfcf91fac9f3d95e5a117429a40ed2ff45a",
58
58
  "skills/age-gates-child-safety/skill.md": "b8fad37033ba955eee678950963e816b6c56fd34a953e5c81b3bdd4c12a8f69a",
59
59
  "skills/cloud-iam-incident/skill.md": "5ec3800a0049b2123aff67bfab4ff28491a86d2daeb712283e5e88b10c3d5d7b",
@@ -78,7 +78,7 @@
78
78
  "handoff_dag_nodes": 42,
79
79
  "summary_cards": 42,
80
80
  "section_offsets_skills": 42,
81
- "token_budget_total_approx": 416979,
81
+ "token_budget_total_approx": 417973,
82
82
  "recipes": 8,
83
83
  "jurisdiction_clocks": 29,
84
84
  "did_ladders": 8,
@@ -183,7 +183,7 @@
183
183
  },
184
184
  "global-frameworks.json": {
185
185
  "path": "data/global-frameworks.json",
186
- "purpose": "Multi-jurisdiction framework registry: 34 jurisdictions × applicable frameworks × patch_sla / notification_sla / critical_controls / framework_gaps. Cross-cutting authority for jurisdiction-clocks index.",
186
+ "purpose": "Multi-jurisdiction framework registry: 35 jurisdictions × applicable frameworks × patch_sla / notification_sla / critical_controls / framework_gaps. Cross-cutting authority for jurisdiction-clocks index.",
187
187
  "schema_version": "1.3.0",
188
188
  "last_updated": "2026-05-15",
189
189
  "tlp": "CLEAR",
@@ -126,6 +126,7 @@
126
126
  "mcp-agent-trust"
127
127
  ],
128
128
  "pqc-first": [
129
+ "ai-c2-detection",
129
130
  "compliance-theater",
130
131
  "framework-gap-analysis"
131
132
  ],
@@ -513,7 +514,7 @@
513
514
  "in_degree": {
514
515
  "age-gates-child-safety": 1,
515
516
  "ai-attack-surface": 26,
516
- "ai-c2-detection": 12,
517
+ "ai-c2-detection": 13,
517
518
  "ai-risk-management": 5,
518
519
  "api-security": 4,
519
520
  "attack-surface-pentest": 13,
@@ -581,7 +582,7 @@
581
582
  "mlops-security": 10,
582
583
  "ot-ics-security": 14,
583
584
  "policy-exception-gen": 0,
584
- "pqc-first": 2,
585
+ "pqc-first": 3,
585
586
  "rag-pipeline-security": 6,
586
587
  "ransomware-response": 10,
587
588
  "researcher": 37,