@aiwg/cli 2026.9.21 → 2026.10.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.
Files changed (210) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +2 -1
  2. package/dist/src/artifacts/cli.js +23 -18
  3. package/dist/src/artifacts/discovery-shadow-evaluator.js +177 -0
  4. package/dist/src/artifacts/discovery-shadow.js +195 -0
  5. package/dist/src/artifacts/fortemi-core-query-adapter.js +6 -2
  6. package/dist/src/artifacts/index-builder.js +47 -9
  7. package/dist/src/artifacts/query-engine.js +108 -5
  8. package/dist/src/artifacts/types.js +1 -0
  9. package/dist/src/cli/handlers/decision.js +88 -0
  10. package/dist/src/cli/handlers/gates.js +154 -0
  11. package/dist/src/cli/handlers/index.js +5 -1
  12. package/dist/src/cli/handlers/sessions.js +10 -7
  13. package/dist/src/cli/handlers/utilities.js +20 -0
  14. package/dist/src/config/aiwg-config.js +15 -2
  15. package/dist/src/decision/acceptance.js +25 -0
  16. package/dist/src/decision/adapters/jev.js +24 -2
  17. package/dist/src/decision/calibration/registry.js +9 -0
  18. package/dist/src/decision/compose.js +74 -15
  19. package/dist/src/decision/context-live-promotion.js +344 -0
  20. package/dist/src/decision/context-live-qualification.js +591 -0
  21. package/dist/src/decision/context-pruning.js +847 -0
  22. package/dist/src/decision/driver.js +430 -0
  23. package/dist/src/decision/egress-live-qualification.js +874 -0
  24. package/dist/src/decision/ensemble/contract.js +64 -1
  25. package/dist/src/decision/ensemble/index.js +1 -0
  26. package/dist/src/decision/ensemble/report.js +8 -42
  27. package/dist/src/decision/ensemble/runtime.js +571 -0
  28. package/dist/src/decision/ensemble-study/artifacts.js +85 -0
  29. package/dist/src/decision/ensemble-study/calibration.js +443 -0
  30. package/dist/src/decision/ensemble-study/corpus.js +229 -0
  31. package/dist/src/decision/ensemble-study/multifact-artifacts.js +23 -0
  32. package/dist/src/decision/ensemble-study/multifact-study.js +596 -0
  33. package/dist/src/decision/ensemble-study/multifact.js +241 -0
  34. package/dist/src/decision/ensemble-study/protocol.js +77 -0
  35. package/dist/src/decision/ensemble-study/score.js +462 -0
  36. package/dist/src/decision/ensemble-study/staged.js +87 -0
  37. package/dist/src/decision/ensemble-study/statistics.js +84 -0
  38. package/dist/src/decision/evaluate.js +227 -14
  39. package/dist/src/decision/export.js +4 -0
  40. package/dist/src/decision/feature-export.js +1074 -0
  41. package/dist/src/decision/graph-index.js +16 -0
  42. package/dist/src/decision/graph-live-qualification.js +1041 -0
  43. package/dist/src/decision/graph-live-workload.js +245 -0
  44. package/dist/src/decision/graph-skill-bridge.js +21 -3
  45. package/dist/src/decision/heldout/calibration.js +140 -0
  46. package/dist/src/decision/heldout/collector.js +430 -0
  47. package/dist/src/decision/heldout/contract.js +309 -0
  48. package/dist/src/decision/heldout/d29-generator-ids.js +12 -0
  49. package/dist/src/decision/heldout/d29-passage-baseline-v2.js +93 -0
  50. package/dist/src/decision/heldout/d29-passage-baseline-v3.js +100 -0
  51. package/dist/src/decision/heldout/d29-passage-baseline.js +66 -0
  52. package/dist/src/decision/heldout/d29-pools-v8.js +575 -0
  53. package/dist/src/decision/heldout/d29-pools.js +288 -0
  54. package/dist/src/decision/heldout/d29-v6.js +169 -0
  55. package/dist/src/decision/heldout/d29-v7.js +202 -0
  56. package/dist/src/decision/heldout/d29-v8.js +586 -0
  57. package/dist/src/decision/heldout/generator-registry.js +67 -0
  58. package/dist/src/decision/heldout/generators.js +696 -0
  59. package/dist/src/decision/heldout/index.js +8 -0
  60. package/dist/src/decision/heldout/journal.js +346 -0
  61. package/dist/src/decision/heldout/study-generators.js +64 -0
  62. package/dist/src/decision/heldout/types.js +2 -0
  63. package/dist/src/decision/host-policy.js +61 -0
  64. package/dist/src/decision/index.js +11 -0
  65. package/dist/src/decision/interop-profile.v1.json +112 -0
  66. package/dist/src/decision/interop.js +653 -0
  67. package/dist/src/decision/issue-triage/index.js +3 -0
  68. package/dist/src/decision/issue-triage/runtime.js +1069 -0
  69. package/dist/src/decision/issue-triage/types.js +2 -0
  70. package/dist/src/decision/patterns/catalog.js +28 -8
  71. package/dist/src/decision/patterns/playground.js +28 -11
  72. package/dist/src/decision/patterns/specs.js +19 -10
  73. package/dist/src/decision/preprocessed-evidence.js +724 -0
  74. package/dist/src/decision/qualification/capture.js +8 -2
  75. package/dist/src/decision/qualification/gate-evidence.js +19 -4
  76. package/dist/src/decision/qualification/load.js +8 -1
  77. package/dist/src/decision/qualification/quality.js +57 -49
  78. package/dist/src/decision/qualification/release.js +76 -3
  79. package/dist/src/decision/qualification/runner.js +5 -2
  80. package/dist/src/decision/routing/contract.js +175 -0
  81. package/dist/src/decision/routing/index.js +5 -0
  82. package/dist/src/decision/routing/report.js +216 -0
  83. package/dist/src/decision/routing/runtime.js +685 -0
  84. package/dist/src/decision/routing/types.js +2 -0
  85. package/dist/src/decision/sdlc-screening.js +1157 -0
  86. package/dist/src/decision/sensitivity/comparative.js +154 -0
  87. package/dist/src/decision/sensitivity/contract.js +218 -0
  88. package/dist/src/decision/sensitivity/index.js +5 -0
  89. package/dist/src/decision/sensitivity/runtime.js +912 -0
  90. package/dist/src/decision/sensitivity/types.js +2 -0
  91. package/dist/src/decision/validate.js +26 -0
  92. package/dist/src/extensions/commands/definitions.js +38 -0
  93. package/dist/src/extensions/manifest.js +44 -0
  94. package/dist/src/gates/discovery.js +315 -0
  95. package/dist/src/gates/driver.js +388 -0
  96. package/dist/src/gates/evaluate.js +719 -0
  97. package/dist/src/gates/floors.js +255 -0
  98. package/dist/src/gates/index.js +17 -0
  99. package/dist/src/gates/providers/evidence.js +38 -0
  100. package/dist/src/gates/providers/index.js +21 -0
  101. package/dist/src/gates/providers/isolated-child-source.js +446 -0
  102. package/dist/src/gates/providers/loader.js +1069 -0
  103. package/dist/src/gates/providers/paired.js +52 -0
  104. package/dist/src/gates/providers/proportion.js +60 -0
  105. package/dist/src/gates/providers/registry.js +40 -0
  106. package/dist/src/gates/providers/scalar.js +41 -0
  107. package/dist/src/gates/providers/screening.js +53 -0
  108. package/dist/src/gates/providers/types.js +25 -0
  109. package/dist/src/gates/registry.js +1003 -0
  110. package/dist/src/gates/report.js +102 -0
  111. package/dist/src/gates/schema.js +56 -0
  112. package/dist/src/gates/stats/binomial.js +26 -0
  113. package/dist/src/gates/stats/bootstrap.js +62 -0
  114. package/dist/src/gates/stats/clopper-pearson.js +95 -0
  115. package/dist/src/gates/stats/digest.js +26 -0
  116. package/dist/src/gates/stats/error.js +5 -0
  117. package/dist/src/gates/stats/index.js +9 -0
  118. package/dist/src/gates/stats/normal.js +35 -0
  119. package/dist/src/gates/stats/paired.js +120 -0
  120. package/dist/src/gates/stats/splits.js +30 -0
  121. package/dist/src/gates/types.js +8 -0
  122. package/dist/src/governance/redaction.js +14 -4
  123. package/dist/src/mcp/muse-native-config.mjs +123 -0
  124. package/dist/src/mcp/tools/decision.mjs +188 -0
  125. package/dist/src/mcp/tools/subsystems.mjs +2 -0
  126. package/dist/src/providers/capability-matrix.yaml +2 -1
  127. package/dist/src/providers/provider-definitions.js +2 -1
  128. package/dist/src/sessions/adapters/muse.js +336 -39
  129. package/dist/src/sessions/batch-import.js +7 -0
  130. package/dist/src/sessions/workspace-discovery.js +13 -2
  131. package/package.json +1 -1
  132. package/schemas/decision/ConformalFrozenOpenData.v2.schema.json +371 -0
  133. package/schemas/decision/ConformalOpenDataReport.v2.schema.json +421 -0
  134. package/schemas/decision/ConformalPreregistration.v2.schema.json +529 -0
  135. package/schemas/decision/ContextPruningCandidate.v1.schema.json +47 -0
  136. package/schemas/decision/ContextPruningEvaluationReport.v1.schema.json +758 -0
  137. package/schemas/decision/ContextPruningPreregistration.v1.schema.json +175 -0
  138. package/schemas/decision/ContextPruningReceipt.v1.schema.json +72 -0
  139. package/schemas/decision/D17Multifact.v1.schema.json +1851 -0
  140. package/schemas/decision/D17StudyAnalysis.v1.schema.json +42 -0
  141. package/schemas/decision/D17StudyAnalysis.v2.schema.json +51 -0
  142. package/schemas/decision/D17StudyCalibration.v1.schema.json +819 -0
  143. package/schemas/decision/D17StudyDryRun.v1.schema.json +169 -0
  144. package/schemas/decision/D17StudyDryRun.v2.schema.json +239 -0
  145. package/schemas/decision/D17StudyGold.v1.schema.json +108 -0
  146. package/schemas/decision/D17StudyGuide.v1.schema.json +63 -0
  147. package/schemas/decision/D17StudyNativeTemplates.v1.schema.json +619 -0
  148. package/schemas/decision/D17StudyProtocol.v1.schema.json +241 -0
  149. package/schemas/decision/D17StudyReport.v1.schema.json +902 -0
  150. package/schemas/decision/D17StudyReport.v2.schema.json +1319 -0
  151. package/schemas/decision/D17StudyReview.v1.schema.json +175 -0
  152. package/schemas/decision/D17StudySplits.v1.schema.json +217 -0
  153. package/schemas/decision/D29Study.v1.schema.json +1903 -0
  154. package/schemas/decision/D29Study.v2.schema.json +1344 -0
  155. package/schemas/decision/D29Study.v3.schema.json +609 -0
  156. package/schemas/decision/D29Study.v4.schema.json +1133 -0
  157. package/schemas/decision/D29Study.v6.schema.json +1205 -0
  158. package/schemas/decision/D29Study.v7.schema.json +1471 -0
  159. package/schemas/decision/D29Study.v8.schema.json +671 -0
  160. package/schemas/decision/D29Study.v9.schema.json +778 -0
  161. package/schemas/decision/DecisionComparativeReplayAuditSample.v1.schema.json +137 -0
  162. package/schemas/decision/DecisionComparativeReplayCorpus.v1.schema.json +258 -0
  163. package/schemas/decision/DecisionComparativeReplayFreeze.v1.schema.json +74 -0
  164. package/schemas/decision/DecisionComparativeReplayGold.v1.schema.json +50 -0
  165. package/schemas/decision/DecisionComparativeReplayGoldAsset.v1.schema.json +37 -0
  166. package/schemas/decision/DecisionComparativeReplayIntegrity.v1.schema.json +81 -0
  167. package/schemas/decision/DecisionComparativeReplayMembers.v1.schema.json +52 -0
  168. package/schemas/decision/DecisionComparativeReplayPreregistration.v1.schema.json +113 -0
  169. package/schemas/decision/DecisionComparativeReplayReport.v1.schema.json +407 -0
  170. package/schemas/decision/DecisionComparativeReplayReviewPackets.v1.schema.json +260 -0
  171. package/schemas/decision/DecisionComparativeReplaySplit.v1.schema.json +84 -0
  172. package/schemas/decision/DecisionFeatureObservation.v1.schema.json +564 -0
  173. package/schemas/decision/DecisionFeatureSet.v1.schema.json +155 -0
  174. package/schemas/decision/DecisionInteropMapping.v1.schema.json +85 -0
  175. package/schemas/decision/DecisionIssueTriageEvaluationManifest.v1.schema.json +174 -0
  176. package/schemas/decision/DecisionIssueTriageEvaluationReport.v1.schema.json +280 -0
  177. package/schemas/decision/DecisionIssueTriagePilotPack.v1.schema.json +114 -0
  178. package/schemas/decision/DecisionRouteReceipt.v1.schema.json +155 -0
  179. package/schemas/decision/DecisionRoutingPolicy.v1.schema.json +132 -0
  180. package/schemas/decision/DecisionRoutingShadowReport.v1.schema.json +170 -0
  181. package/schemas/decision/DecisionRoutingTask.v1.schema.json +49 -0
  182. package/schemas/decision/DecisionRuleset.schema.json +8 -2
  183. package/schemas/decision/DecisionRuleset.v1alpha2.schema.json +8 -2
  184. package/schemas/decision/DecisionSensitivityPlan.v1.schema.json +191 -0
  185. package/schemas/decision/DecisionSensitivityReport.v1.schema.json +163 -0
  186. package/schemas/decision/HeldoutApproval.v1.schema.json +312 -0
  187. package/schemas/decision/HeldoutAttempt.v1.schema.json +211 -0
  188. package/schemas/decision/HeldoutBaseline.v1.schema.json +90 -0
  189. package/schemas/decision/HeldoutCalibrationPhase.v1.schema.json +87 -0
  190. package/schemas/decision/HeldoutCorpus.v1.schema.json +167 -0
  191. package/schemas/decision/HeldoutEvent.v1.schema.json +41 -0
  192. package/schemas/decision/HeldoutFrozen.v1.schema.json +142 -0
  193. package/schemas/decision/HeldoutPreregistration.v1.schema.json +222 -0
  194. package/schemas/decision/HeldoutSpendEvent.v1.schema.json +122 -0
  195. package/schemas/decision/HeldoutSpendHead.v1.schema.json +25 -0
  196. package/schemas/decision/HeldoutSpendHead.v2.schema.json +46 -0
  197. package/schemas/decision/HeldoutSummary.v1.schema.json +101 -0
  198. package/schemas/decision/OpaDecisionLogExport.v1.schema.json +65 -0
  199. package/schemas/decision/PreprocessedEvidence.v1.schema.json +306 -0
  200. package/schemas/decision/RulesetResult.v1alpha2.schema.json +175 -0
  201. package/schemas/decision/SdlcEvidenceScreening.v1.schema.json +499 -0
  202. package/schemas/decision/SdlcScreeningPreregistration.v1.schema.json +132 -0
  203. package/schemas/decision/SdlcScreeningPreregistration.v2.schema.json +138 -0
  204. package/schemas/decision/SdlcScreeningRelease.v1.schema.json +654 -0
  205. package/schemas/decision/SdlcScreeningRelease.v2.schema.json +654 -0
  206. package/tools/agents/deploy-agents.mjs +1 -1
  207. package/tools/agents/providers/base.mjs +26 -7
  208. package/tools/agents/providers/factory.mjs +10 -2
  209. package/tools/agents/providers/muse-hooks.mjs +1 -29
  210. package/tools/agents/providers/muse.mjs +6 -3
@@ -0,0 +1,8 @@
1
+ export * from './types.js';
2
+ export * from './contract.js';
3
+ export * from './collector.js';
4
+ export * from './journal.js';
5
+ export * from './generators.js';
6
+ export * from './generator-registry.js';
7
+ export * from './study-generators.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,346 @@
1
+ import { lstat, mkdir, open, readdir, readFile, realpath, rename } from 'node:fs/promises';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { heldoutDigest, HeldoutError, heldoutRequest, heldoutReservationMicros, heldoutReservationTokens, validateHeldoutAttempt, validateHeldoutBundle, checkHeldoutSchema, HELDOUT_CAP_USD, HELDOUT_PORTFOLIO_CAP_USD } from './contract.js';
4
+ export const heldoutRunsRoot = (root) => join(root, 'research', 'qualification', 'heldout', 'runs');
5
+ const baselineRoot = (root) => join(root, 'research', 'qualification', 'heldout', 'baselines');
6
+ const counterRoot = (root) => dirname(heldoutRunsRoot(root));
7
+ const chargeKey = (charge) => `${charge.study}/${charge.runId}/${charge.rowId}/${charge.requestId}/${charge.ordinal}`;
8
+ const repair = () => new HeldoutError('spend-counter-operator-repair-required');
9
+ const baselineDigests = (baselines) => Object.fromEntries([...baselines].map(([scope, baseline]) => [scope, heldoutDigest(baseline)]));
10
+ async function counterHead(root, event, baselines) {
11
+ const dir = counterRoot(root), temporary = join(dir, 'spend-head.next.json');
12
+ const head = { schemaVersion: 'decision-heldout-spend-head/v2', sequence: event.sequence, digest: event.digest,
13
+ baselineDigests: baselineDigests(baselines) };
14
+ checkHeldoutSchema('SpendHead', head);
15
+ await writeHeldoutFile(temporary, head);
16
+ await rename(temporary, join(dir, 'spend-head.json'));
17
+ const directory = await open(dir, 'r');
18
+ try {
19
+ await directory.sync();
20
+ }
21
+ finally {
22
+ await directory.close();
23
+ }
24
+ }
25
+ /** The independent head binds baselines and detects valid-prefix truncation after all run files disappear. */
26
+ async function readCounter(root, baselines) {
27
+ const dir = counterRoot(root), path = join(dir, 'spend-counter.jsonl');
28
+ const names = await readdir(dir);
29
+ if (!names.includes('spend-counter.jsonl') && !baselines.size && !names.includes('spend-head.json')
30
+ && !names.includes('spend-head.next.json'))
31
+ return { events: [], studies: new Map(), blocked: false };
32
+ try {
33
+ if (names.includes('spend-head.next.json'))
34
+ throw repair();
35
+ const stat = await lstat(path);
36
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32_000_000)
37
+ throw repair();
38
+ const bytes = await readFile(path, 'utf8');
39
+ if (!bytes.endsWith('\n'))
40
+ throw repair();
41
+ const events = [], studies = new Map(), latest = new Map();
42
+ let total = 0;
43
+ for (const line of bytes.slice(0, -1).split('\n')) {
44
+ const event = JSON.parse(line);
45
+ checkHeldoutSchema('SpendEvent', event);
46
+ const { digest, ...payload } = event;
47
+ if (event.sequence !== events.length + 1 || event.previous !== (events.at(-1)?.digest ?? null)
48
+ || digest !== heldoutDigest(payload) || (events.length === 0) !== (event.charge === null))
49
+ throw repair();
50
+ const charge = event.charge;
51
+ if (charge) {
52
+ const key = chargeKey(charge), prior = latest.get(key);
53
+ if (charge.accountedUsdMicros === null ? prior || charge.disposition !== null
54
+ : !prior || prior.accountedUsdMicros !== null || charge.disposition === null
55
+ || charge.reservedTokens !== prior.reservedTokens || charge.reservedUsdMicros !== prior.reservedUsdMicros || charge.accountedUsdMicros < charge.reservedUsdMicros)
56
+ throw repair();
57
+ const delta = charge.accountedUsdMicros === null ? charge.reservedUsdMicros : charge.accountedUsdMicros - charge.reservedUsdMicros;
58
+ total += delta;
59
+ studies.set(charge.study, (studies.get(charge.study) ?? 0) + delta);
60
+ latest.set(key, charge);
61
+ }
62
+ if (event.totalUsdMicros !== total || !Number.isSafeInteger(total))
63
+ throw repair();
64
+ events.push(event);
65
+ }
66
+ const head = await readHeldoutFile(join(dir, 'spend-head.json'));
67
+ checkHeldoutSchema('SpendHead', head);
68
+ if (head.sequence !== events.length || head.digest !== events.at(-1)?.digest
69
+ || heldoutDigest(head.baselineDigests) !== heldoutDigest(baselineDigests(baselines))
70
+ || [...baselines.values()].some(b => b.counterGenesisDigest !== events[0].digest))
71
+ throw repair();
72
+ if (!baselines.has('portfolio') || [...studies.keys()].some(study => !baselines.has(study)))
73
+ throw repair();
74
+ return { events, studies, blocked: [...latest.values()].some(c => c.disposition === null || c.disposition === 'stop') };
75
+ }
76
+ catch {
77
+ throw repair();
78
+ }
79
+ }
80
+ /** Caller holds the global dispatch lock. Never rewrite or refund a counter entry. */
81
+ export async function appendHeldoutSpend(root, attempt) {
82
+ const baselines = await readBaselines(root), counter = await readCounter(root, baselines);
83
+ const charge = { study: attempt.study, runId: attempt.runId, rowId: attempt.rowId, requestId: attempt.requestId,
84
+ ordinal: attempt.ordinal, reservedUsdMicros: attempt.reservedUsdMicros, reservedTokens: attempt.reservedTokens,
85
+ accountedUsdMicros: attempt.result?.accountedUsdMicros ?? null, disposition: attempt.result?.disposition ?? null };
86
+ validateHeldoutAttempt(attempt);
87
+ const prior = [...counter.events].reverse().find(event => event.charge && chargeKey(event.charge) === chargeKey(charge))?.charge;
88
+ if (attempt.result ? !prior || prior.accountedUsdMicros !== null || prior.reservedUsdMicros !== charge.reservedUsdMicros || prior.reservedTokens !== charge.reservedTokens
89
+ || attempt.result.accountedUsdMicros < attempt.reservedUsdMicros : prior)
90
+ throw repair();
91
+ const delta = attempt.result ? attempt.result.accountedUsdMicros - attempt.reservedUsdMicros : attempt.reservedUsdMicros;
92
+ const payload = { schemaVersion: 'decision-heldout-spend-event/v1', sequence: counter.events.length + 1,
93
+ previous: counter.events.at(-1).digest, charge, totalUsdMicros: counter.events.at(-1).totalUsdMicros + delta };
94
+ const event = { ...payload, digest: heldoutDigest(payload) };
95
+ checkHeldoutSchema('SpendEvent', event);
96
+ const file = await open(join(counterRoot(root), 'spend-counter.jsonl'), 'a');
97
+ try {
98
+ await file.writeFile(JSON.stringify(event) + '\n');
99
+ await file.sync();
100
+ }
101
+ finally {
102
+ await file.close();
103
+ }
104
+ await counterHead(root, event, baselines);
105
+ }
106
+ async function readBaselines(root) {
107
+ await heldoutDirectory(baselineRoot(root));
108
+ const baselines = new Map();
109
+ for (const name of await readdir(baselineRoot(root))) {
110
+ const baseline = await readHeldoutFile(join(baselineRoot(root), name));
111
+ checkHeldoutSchema('Baseline', baseline);
112
+ if (name !== `${baseline.scope}.json`)
113
+ throw new HeldoutError('baseline-path');
114
+ baselines.set(baseline.scope, baseline);
115
+ }
116
+ return baselines;
117
+ }
118
+ function checkBaselineApproval(baselines, approval) {
119
+ for (const [scope, usd] of [[approval.study, approval.priorStudySpendUsd], ['portfolio', approval.priorPortfolioSpendUsd]]) {
120
+ if (baselines.has(scope) && baselines.get(scope).usdMicros !== Math.ceil(usd * 1_000_000))
121
+ throw new HeldoutError('baseline-changed');
122
+ }
123
+ const study = baselines.get(approval.study);
124
+ if (study && heldoutDigest(study.budget) !== heldoutDigest(approval.budget))
125
+ throw new HeldoutError('budget-changed');
126
+ }
127
+ /** Called under the global dispatch lock, after checking existing journals. Floors and study budgets are recorded once. */
128
+ export async function reconcileHeldoutBaseline(root, approval) {
129
+ const baselines = await readBaselines(root);
130
+ const counter = await readCounter(root, baselines);
131
+ checkBaselineApproval(baselines, approval);
132
+ let head = counter.events.at(-1);
133
+ if (!head) {
134
+ const payload = { schemaVersion: 'decision-heldout-spend-event/v1', sequence: 1, previous: null, charge: null, totalUsdMicros: 0 };
135
+ head = { ...payload, digest: heldoutDigest(payload) };
136
+ await writeHeldoutFile(join(counterRoot(root), 'spend-counter.jsonl'), head);
137
+ }
138
+ const genesis = counter.events[0]?.digest ?? head.digest;
139
+ let changed = false;
140
+ for (const [scope, usd] of [[approval.study, approval.priorStudySpendUsd], ['portfolio', approval.priorPortfolioSpendUsd]]) {
141
+ const usdMicros = Math.ceil(usd * 1_000_000), baseline = baselines.get(scope);
142
+ if (!baseline) {
143
+ const recorded = { schemaVersion: 'decision-heldout-baseline/v1', scope, usdMicros,
144
+ approvalDigest: heldoutDigest(approval), counterGenesisDigest: genesis, budget: scope === 'portfolio' ? null : approval.budget };
145
+ await writeHeldoutFile(join(baselineRoot(root), `${scope}.json`), recorded);
146
+ baselines.set(scope, recorded);
147
+ changed = true;
148
+ }
149
+ }
150
+ // Publish only after every baseline is durable. A partial update fails closed on the next read.
151
+ if (changed)
152
+ await counterHead(root, head, baselines);
153
+ const recorded = await readBaselines(root);
154
+ return { study: heldoutDigest(recorded.get(approval.study)), portfolio: heldoutDigest(recorded.get('portfolio')) };
155
+ }
156
+ /** Reject symlinked journal ancestors as well as leaves: spend cannot be redirected to another root. */
157
+ export async function heldoutDirectory(path) {
158
+ await mkdir(path, { recursive: true, mode: 0o700 });
159
+ if (await realpath(path) !== resolve(path))
160
+ throw new HeldoutError('artifact-symlink');
161
+ }
162
+ export async function writeHeldoutFile(path, value) {
163
+ const file = await open(path, 'wx', 0o600);
164
+ try {
165
+ await file.writeFile(JSON.stringify(value) + '\n');
166
+ await file.sync();
167
+ }
168
+ finally {
169
+ await file.close();
170
+ }
171
+ const directory = await open(dirname(path), 'r');
172
+ try {
173
+ await directory.sync();
174
+ }
175
+ finally {
176
+ await directory.close();
177
+ }
178
+ }
179
+ export async function readHeldoutFile(path) {
180
+ const stat = await lstat(path);
181
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32_000_000)
182
+ throw new HeldoutError('artifact-file');
183
+ return JSON.parse(await readFile(path, 'utf8'));
184
+ }
185
+ export async function readHeldoutJournal(run) {
186
+ if (await realpath(run) !== resolve(run))
187
+ throw new HeldoutError('artifact-symlink');
188
+ const entries = (await readdir(run)).filter(name => /^\d{8}\.json$/.test(name)).sort();
189
+ const events = [];
190
+ const pending = new Map();
191
+ const seen = new Set();
192
+ for (const name of entries) {
193
+ const event = await readHeldoutFile(join(run, name));
194
+ checkHeldoutSchema('Event', event);
195
+ const { digest, ...payload } = event;
196
+ if (Object.keys(event).sort().join(',') !== 'attempt,digest,previous,schemaVersion,sequence'
197
+ || event.sequence !== events.length + 1 || name !== `${String(event.sequence).padStart(8, '0')}.json`
198
+ || event.previous !== (events.at(-1)?.digest ?? null) || digest !== heldoutDigest(payload))
199
+ throw new HeldoutError('journal-chain');
200
+ validateHeldoutAttempt(event.attempt);
201
+ const attempt = event.attempt, key = `${attempt.rowId}/${attempt.requestId}/${attempt.ordinal}`;
202
+ if (!attempt.result) {
203
+ if (seen.has(key))
204
+ throw new HeldoutError('duplicate-reservation');
205
+ seen.add(key);
206
+ pending.set(key, attempt);
207
+ }
208
+ else {
209
+ const reservation = pending.get(key);
210
+ if (!reservation || heldoutDigest({ ...attempt, result: null }) !== heldoutDigest(reservation))
211
+ throw new HeldoutError('unreserved-result');
212
+ pending.delete(key);
213
+ const trace = await readHeldoutFile(join(run, `trace-${event.sequence - 1}.json`));
214
+ if (heldoutDigest(trace) !== attempt.result.traceDigest)
215
+ throw new HeldoutError('trace-digest');
216
+ }
217
+ events.push(event);
218
+ }
219
+ return events;
220
+ }
221
+ export async function appendHeldoutEvent(run, events, attempt) {
222
+ validateHeldoutAttempt(attempt);
223
+ const payload = { schemaVersion: 'decision-heldout-event/v1', sequence: events.length + 1, previous: events.at(-1)?.digest ?? null, attempt: structuredClone(attempt) };
224
+ const event = { ...payload, digest: heldoutDigest(payload) };
225
+ await writeHeldoutFile(join(run, `${String(event.sequence).padStart(8, '0')}.json`), event);
226
+ events.push(event);
227
+ }
228
+ export async function heldoutEvidenceDigest(run, events) {
229
+ return heldoutDigest({ frozenDigest: heldoutDigest(await readHeldoutFile(join(run, 'frozen.json'))),
230
+ journalDigest: events.at(-1)?.digest ?? heldoutDigest([]) });
231
+ }
232
+ /** Count reservations, including crashes and failed requests; successful small usage never refunds spend. */
233
+ export async function scanHeldoutSpend(root, study, approval) {
234
+ const runs = heldoutRunsRoot(root);
235
+ await heldoutDirectory(runs);
236
+ const baselines = await readBaselines(root);
237
+ if (approval) {
238
+ if (approval.study !== study)
239
+ throw new HeldoutError('baseline-study');
240
+ checkBaselineApproval(baselines, approval);
241
+ }
242
+ const counter = await readCounter(root, baselines);
243
+ const result = { studyUsdMicros: baselines.get(study)?.usdMicros ?? 0,
244
+ portfolioUsdMicros: baselines.get('portfolio')?.usdMicros ?? 0, studyCalls: 0, studyReservedTokens: 0, counterBlocked: counter.blocked, attempts: [], journalDigests: [], runs: [] };
245
+ for (const { charge } of counter.events)
246
+ if (charge?.study === study && charge.accountedUsdMicros === null) {
247
+ result.studyCalls++;
248
+ result.studyReservedTokens += charge.reservedTokens;
249
+ }
250
+ for (const name of (await readdir(runs)).sort()) {
251
+ if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(name))
252
+ throw new HeldoutError('run-path');
253
+ const run = join(runs, name);
254
+ const frozen = await readHeldoutFile(join(run, 'frozen.json'));
255
+ checkHeldoutSchema('Frozen', frozen);
256
+ if (frozen.approval?.runId !== name || !['D17', 'D29'].includes(frozen.approval.study)
257
+ || frozen.digest !== heldoutDigest(frozen.bundle))
258
+ throw new HeldoutError('frozen-inputs');
259
+ validateHeldoutBundle(frozen.bundle, heldoutDigest(frozen.bundle.approval));
260
+ const approval = frozen.bundle.approval;
261
+ if (baselines.get(approval.study)?.usdMicros !== Math.ceil(approval.priorStudySpendUsd * 1_000_000)
262
+ || baselines.get('portfolio')?.usdMicros !== Math.ceil(approval.priorPortfolioSpendUsd * 1_000_000))
263
+ throw new HeldoutError('baseline-mismatch');
264
+ if (frozen.baselineDigests.study !== heldoutDigest(baselines.get(approval.study))
265
+ || frozen.baselineDigests.portfolio !== heldoutDigest(baselines.get('portfolio')))
266
+ throw new HeldoutError('baseline-mismatch');
267
+ if (frozen.bundle.approval.runId !== name || frozen.bundle.approval.study !== frozen.approval.study)
268
+ throw new HeldoutError('frozen-run');
269
+ for (const prior of frozen.priorRuns) {
270
+ if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(prior.runId) || prior.runId === name)
271
+ throw new HeldoutError('prior-run');
272
+ const path = join(runs, prior.runId);
273
+ if (await heldoutEvidenceDigest(path, await readHeldoutJournal(path)) !== prior.evidenceDigest)
274
+ throw new HeldoutError('prior-evidence');
275
+ }
276
+ const events = await readHeldoutJournal(run);
277
+ await validateHeldoutJournal(frozen.bundle, events);
278
+ if ((await readdir(run)).includes('summary.json')) {
279
+ const summary = await readHeldoutFile(join(run, 'summary.json'));
280
+ checkHeldoutSchema('Summary', summary);
281
+ if (summary.evidenceDigest !== await heldoutEvidenceDigest(run, events))
282
+ throw new HeldoutError('truncated-journal');
283
+ }
284
+ result.runs.push({ runId: name, evidenceDigest: await heldoutEvidenceDigest(run, events), corpusDigest: frozen.bundle.approval.corpusDigest, study: frozen.approval.study, source: frozen.source });
285
+ const latest = new Map();
286
+ for (const { attempt } of events) {
287
+ if (attempt.runId !== name || attempt.study !== frozen.approval.study)
288
+ throw new HeldoutError('journal-run');
289
+ const key = `${attempt.rowId}/${attempt.requestId}/${attempt.ordinal}`;
290
+ if (!attempt.result) {
291
+ result.portfolioUsdMicros += attempt.reservedUsdMicros;
292
+ if (attempt.study === study)
293
+ result.studyUsdMicros += attempt.reservedUsdMicros;
294
+ }
295
+ else {
296
+ if (attempt.result.accountedUsdMicros < attempt.reservedUsdMicros)
297
+ throw new HeldoutError('reservation-refund');
298
+ const extra = attempt.result.accountedUsdMicros - attempt.reservedUsdMicros;
299
+ result.portfolioUsdMicros += extra;
300
+ if (attempt.study === study)
301
+ result.studyUsdMicros += extra;
302
+ }
303
+ latest.set(key, attempt);
304
+ }
305
+ result.attempts.push(...latest.values());
306
+ if (events.length)
307
+ result.journalDigests.push(events.at(-1).digest);
308
+ }
309
+ result.studyUsdMicros = Math.max(result.studyUsdMicros, (baselines.get(study)?.usdMicros ?? 0) + (counter.studies.get(study) ?? 0));
310
+ result.portfolioUsdMicros = Math.max(result.portfolioUsdMicros, (baselines.get('portfolio')?.usdMicros ?? 0) + (counter.events.at(-1)?.totalUsdMicros ?? 0));
311
+ // A first-run preview includes its proposed baseline without writing it or reusing a max floor.
312
+ if (approval && !baselines.has(study))
313
+ result.studyUsdMicros += Math.ceil(approval.priorStudySpendUsd * 1_000_000);
314
+ if (approval && !baselines.has('portfolio'))
315
+ result.portfolioUsdMicros += Math.ceil(approval.priorPortfolioSpendUsd * 1_000_000);
316
+ return result;
317
+ }
318
+ /** Replay enforces the same membership, phase and reservation pins as dispatch. */
319
+ export async function validateHeldoutJournal(bundle, events) {
320
+ for (const { attempt } of events) {
321
+ if (attempt.runId !== bundle.approval.runId || attempt.study !== bundle.approval.study)
322
+ throw new HeldoutError('journal-run');
323
+ const approved = bundle.approval;
324
+ const row = bundle.corpus.rows.find(row => row.id === attempt.rowId);
325
+ const request = row?.requests.find(request => request.id === attempt.requestId);
326
+ if (!row || !request)
327
+ throw new HeldoutError('journal-pins');
328
+ const planned = await heldoutRequest(bundle.corpus, bundle.preregistration, approved, row, request);
329
+ if (attempt.corpusDigest !== approved.corpusDigest || attempt.preregistrationDigest !== approved.preregistrationDigest
330
+ || attempt.approvalDigest !== heldoutDigest(approved) || attempt.requestDigest !== planned.requestDigest
331
+ || attempt.reservedUsdMicros !== heldoutReservationMicros(approved, planned.estimatedTokens)
332
+ || attempt.reservedTokens !== heldoutReservationTokens(bundle.preregistration, planned.estimatedTokens))
333
+ throw new HeldoutError('journal-pins');
334
+ }
335
+ }
336
+ /** Every mode shares fixed thresholds; admission checks the approval against its durable study baseline. */
337
+ export function heldoutCollectionAllowance(approval, prior) {
338
+ const studyRemaining = HELDOUT_CAP_USD[approval.study] * 1_000_000 - prior.studyUsdMicros;
339
+ const portfolioRemaining = HELDOUT_PORTFOLIO_CAP_USD * 1_000_000 - prior.portfolioUsdMicros;
340
+ const studySpent = prior.studyUsdMicros - Math.ceil(approval.priorStudySpendUsd * 1_000_000);
341
+ const portfolioSpent = prior.portfolioUsdMicros - Math.ceil(approval.priorPortfolioSpendUsd * 1_000_000);
342
+ return { calls: Math.floor(approval.budget.calls * 0.8) - prior.studyCalls,
343
+ tokens: Math.floor(approval.budget.tokens * 0.8) - prior.studyReservedTokens,
344
+ usdMicros: Math.min(Math.floor(approval.budget.usd * 800_000) - studySpent, Math.floor((studyRemaining + studySpent) * 0.8) - studySpent, Math.floor((portfolioRemaining + portfolioSpent) * 0.8) - portfolioSpent) };
345
+ }
346
+ //# sourceMappingURL=journal.js.map
@@ -0,0 +1,64 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { sha256 } from '../compile-cache/identity.js';
3
+ import { generateRegisteredHeldoutRow, registeredHeldoutGeneratorDigest, registeredHeldoutGeneratorFiles, reproducibleRegisteredHeldoutRow } from './generator-registry.js';
4
+ import { d17MfGenerateCase } from '../ensemble-study/multifact.js';
5
+ /**
6
+ * Outer held-out generator registry for study generators added after D29 v8 (#2850).
7
+ *
8
+ * `generators.ts` and `generator-registry.ts` are themselves hashed into the D29 v1-v8 generator pins, so editing either
9
+ * would move committed corpus pins. New study generators register here instead: this module answers for its own ids and
10
+ * delegates every other id to the existing registries unchanged. Each id hashes only its own sources. Source-controlled
11
+ * only: corpus data cannot register code or supply a module path.
12
+ */
13
+ export const D17_MULTIFACT_GENERATOR_ID = 'd17-multifact/v1';
14
+ // The generator and the hash it imports for draws and record digests.
15
+ const D17_MULTIFACT_SOURCES = ['src/decision/ensemble-study/multifact.ts', 'src/decision/compile-cache/identity.ts'];
16
+ export function generateStudyHeldoutRow(generatorId, seed) {
17
+ if (generatorId !== D17_MULTIFACT_GENERATOR_ID)
18
+ return generateRegisteredHeldoutRow(generatorId, seed);
19
+ const output = d17MfGenerateCase(seed).row;
20
+ return { ...output, provenance: { generatorId, seed, outputDigest: sha256(output) } };
21
+ }
22
+ export function reproducibleStudyHeldoutRow(row) {
23
+ if (row?.provenance?.generatorId !== D17_MULTIFACT_GENERATOR_ID)
24
+ return reproducibleRegisteredHeldoutRow(row);
25
+ const { provenance, ...output } = row;
26
+ try {
27
+ const regenerated = d17MfGenerateCase(provenance.seed).row;
28
+ return sha256(regenerated) === provenance.outputDigest && sha256(output) === provenance.outputDigest;
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ export function studyHeldoutGeneratorFiles(generatorId) {
35
+ return generatorId === D17_MULTIFACT_GENERATOR_ID ? [...D17_MULTIFACT_SOURCES] : registeredHeldoutGeneratorFiles(generatorId);
36
+ }
37
+ export function studyHeldoutGeneratorDigest(generatorId) {
38
+ if (generatorId !== D17_MULTIFACT_GENERATOR_ID)
39
+ return registeredHeldoutGeneratorDigest(generatorId);
40
+ const sources = {};
41
+ for (const file of D17_MULTIFACT_SOURCES)
42
+ sources[file] = readFileSync(new URL(`../../../${file}`, import.meta.url), 'utf8');
43
+ return sha256(sources);
44
+ }
45
+ /**
46
+ * D17-MF collector-boundary policy, keyed on the generator id the way D29's paid-generator rule is (#2850). It is enforced
47
+ * by `validateHeldoutBundle` and the collector, so a hand-built bundle cannot skip the CLI's checks.
48
+ *
49
+ * - Public seeds: committed or review seeds regenerate gold from source. A private seed must also carry at least 24
50
+ * lowercase hex characters of fresh randomness, so memorable or committed near-variants are refused too.
51
+ * - Calibration window: the probe is scored only through the registered D17 member calibrator, which expires at its
52
+ * `effectiveAt` (2026-10-02T10:02:34.263Z) plus the D17 profile's 30 days. No session may dispatch past it.
53
+ */
54
+ export const D17_MULTIFACT_CALIBRATION_NOT_AFTER = '2026-11-01T10:02:34.263Z';
55
+ export const D17_MULTIFACT_PUBLIC_SEEDS = Object.freeze(['d17mf-offline', 'd17mf-public-demo', 'd17mf-smoke',
56
+ 'd17mf-7f3a9c2e1b', 'review-throwaway-a1', 'review-throwaway-b2']);
57
+ export function d17MultifactPublicSeed(seed) {
58
+ return typeof seed !== 'string' || D17_MULTIFACT_PUBLIC_SEEDS.includes(seed)
59
+ || /^(review-|d17mf-(offline|public|smoke|sweep|demo))/.test(seed) || !/[0-9a-f]{24}/.test(seed);
60
+ }
61
+ export function usesD17MultifactGenerator(rows) {
62
+ return Array.isArray(rows) && rows.some(row => row?.provenance?.generatorId === D17_MULTIFACT_GENERATOR_ID);
63
+ }
64
+ //# sourceMappingURL=study-generators.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,61 @@
1
+ const HOST_POLICY_KEYS = [
2
+ 'batching',
3
+ 'batchReceipts',
4
+ 'context',
5
+ 'scheduler',
6
+ 'compileCache',
7
+ 'resultCache',
8
+ 'providerPrefix',
9
+ ];
10
+ const KEY_SET = new Set(HOST_POLICY_KEYS);
11
+ const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
12
+ function isRecord(value) {
13
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
14
+ }
15
+ export function assertDecisionHostPolicyRefs(value) {
16
+ if (!isRecord(value))
17
+ throw new Error('hostPolicies must be an object of named trusted host-policy references');
18
+ for (const [key, ref] of Object.entries(value)) {
19
+ if (!KEY_SET.has(key))
20
+ throw new Error(`Unsupported decision host policy '${key}'. Supported policies: ${HOST_POLICY_KEYS.join(', ')}`);
21
+ if (typeof ref !== 'string' || !ref.trim())
22
+ throw new Error(`hostPolicies.${key} must name a trusted host policy`);
23
+ }
24
+ }
25
+ export function resolveDecisionHostPolicies(refs, registry = {}) {
26
+ if (refs === undefined)
27
+ return {};
28
+ assertDecisionHostPolicyRefs(refs);
29
+ const resolved = {};
30
+ for (const [key, ref] of Object.entries(refs)) {
31
+ const group = hasOwn(registry, key) ? registry[key] : undefined;
32
+ const policy = group && hasOwn(group, ref) ? group[ref] : undefined;
33
+ if (!policy)
34
+ throw new Error(`Unknown trusted decision host policy '${key}:${ref}'`);
35
+ resolved[key] = policy;
36
+ }
37
+ return resolved;
38
+ }
39
+ export function assertNoInlineDecisionHostPolicies(config) {
40
+ for (const key of HOST_POLICY_KEYS) {
41
+ if (key in config)
42
+ throw new Error(`Unsupported inline decision runtime option '${key}'. Use hostPolicies.${key} to select a trusted host policy`);
43
+ }
44
+ }
45
+ export function assertDecisionEvaluateDispatcherConfig(config) {
46
+ if (!isRecord(config))
47
+ throw new Error('decision-evaluate request must be a JSON object');
48
+ assertNoInlineDecisionHostPolicies(config);
49
+ const allowed = new Set([
50
+ 'rulesetPath', 'bindingPath', 'definitionPaths', 'inputPath', 'runId', 'invocationId',
51
+ 'receiptDirectory', 'receiptIntegrityKeyRef', 'receiptIntegrityKeyEncoding',
52
+ 'credentials', 'adapterOptions', 'adapterModules', 'projectionPolicyPath', 'hostPolicies',
53
+ ]);
54
+ for (const key of Object.keys(config)) {
55
+ if (!allowed.has(key))
56
+ throw new Error(`Unsupported decision-evaluate request field '${key}'`);
57
+ }
58
+ if ('hostPolicies' in config)
59
+ assertDecisionHostPolicyRefs(config.hostPolicies);
60
+ }
61
+ //# sourceMappingURL=host-policy.js.map
@@ -27,14 +27,19 @@ export * from './admission.js';
27
27
  export * from './batch-receipts/index.js';
28
28
  export * from './context-plan.js';
29
29
  export * from './context-qualification.js';
30
+ export * from './context-pruning.js';
30
31
  export * from './calibration/index.js';
31
32
  export * from './projection.js';
33
+ export * from './preprocessed-evidence.js';
32
34
  export * from './lifecycle.js';
33
35
  export * from './file-lifecycle-store.js';
34
36
  export * from './receipts.js';
35
37
  export * from './portable-secrets.js';
36
38
  export * from './evaluate.js';
39
+ export * from './host-policy.js';
37
40
  export * from './export.js';
41
+ export * from './feature-export.js';
42
+ export * from './sdlc-screening.js';
38
43
  export * from './adapters/jev.js';
39
44
  export * from './adapters/llm-subagent.js';
40
45
  export * from './review/index.js';
@@ -44,4 +49,10 @@ export * from './patterns/index.js';
44
49
  export * from './compile-cache/index.js';
45
50
  export * from './result-cache/index.js';
46
51
  export * from './ensemble/index.js';
52
+ export * from './sensitivity/index.js';
53
+ export * from './issue-triage/index.js';
54
+ export * from './routing/index.js';
55
+ export * from './interop.js';
56
+ export { collectHeldoutStudy, scoreHeldoutStudy } from './heldout/collector.js';
57
+ export { heldoutDigest, heldoutExecutionDigest, planHeldoutCollection, validateHeldoutBundle, heldoutRowsInScope } from './heldout/contract.js';
47
58
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,112 @@
1
+ {
2
+ "apiVersion": "decision-interop.aiwg.io/v1",
3
+ "kind": "DecisionInteropProfile",
4
+ "metadata": {
5
+ "id": "aiwg-decision-dmn-opa-interop",
6
+ "version": "1.0.0",
7
+ "description": "AIWG deterministic decision interoperability profile for a safe DMN 1.6 subset and OPA decision-log exchange"
8
+ },
9
+ "spec": {
10
+ "dmn": {
11
+ "version": "1.6",
12
+ "namespace": "https://www.omg.org/spec/DMN/20240513/MODEL/",
13
+ "supportedElements": [
14
+ "definitions",
15
+ "decision",
16
+ "informationRequirement",
17
+ "requiredDecision",
18
+ "decisionTable",
19
+ "input",
20
+ "inputExpression",
21
+ "output",
22
+ "rule",
23
+ "inputEntry",
24
+ "outputEntry",
25
+ "text"
26
+ ],
27
+ "hitPolicies": [
28
+ "UNIQUE",
29
+ "ANY",
30
+ "FIRST",
31
+ "RULE ORDER",
32
+ "COLLECT"
33
+ ],
34
+ "collectAggregations": [
35
+ "LIST",
36
+ "SUM",
37
+ "MIN",
38
+ "MAX",
39
+ "COUNT"
40
+ ],
41
+ "comparisons": [
42
+ "dash",
43
+ "literal",
44
+ "eq",
45
+ "ne",
46
+ "lt",
47
+ "lte",
48
+ "gt",
49
+ "gte"
50
+ ],
51
+ "extensions": [
52
+ "aiwg:order",
53
+ "aiwg:defer-on-conflict"
54
+ ],
55
+ "exclusions": [
56
+ "arbitrary FEEL expressions",
57
+ "literalExpression execution",
58
+ "scripts",
59
+ "businessKnowledgeModel",
60
+ "imports",
61
+ "remote references",
62
+ "XInclude",
63
+ "DTD",
64
+ "external entities",
65
+ "missing dependency pins"
66
+ ],
67
+ "dependencyProfile": {
68
+ "mode": "local-acyclic-external-evidence",
69
+ "pinAuthority": "caller-supplied ArtifactPin values only; XML never establishes trusted AIWG decision authority",
70
+ "unsupported": [
71
+ "cycles",
72
+ "executable dependency decisions",
73
+ "remote hrefs",
74
+ "missing external decision pins"
75
+ ],
76
+ "nativeMapping": "required decisions become decision-source predicates and normalized ruleset evaluations"
77
+ }
78
+ },
79
+ "opa": {
80
+ "input": "default-deny structured JSON evidence projection with explicit reviewed JSON-pointer allowlist",
81
+ "result": "deterministic policy output only",
82
+ "bundlePins": [
83
+ "name",
84
+ "revision",
85
+ "digest"
86
+ ],
87
+ "decisionLogFields": [
88
+ "decision_id",
89
+ "trace_id",
90
+ "span_id",
91
+ "bundles.<name>.revision",
92
+ "metrics",
93
+ "revisionLineage"
94
+ ],
95
+ "defaultRedaction": [
96
+ "raw",
97
+ "body",
98
+ "secret",
99
+ "token",
100
+ "credential",
101
+ "private",
102
+ "locator",
103
+ "state",
104
+ "authorization",
105
+ "password",
106
+ "key"
107
+ ],
108
+ "enforcement": "separate PEP/action contract; OPA/DMN decisions do not authorize AIWG actions"
109
+ },
110
+ "activation": "dry-run imports only; review/publish path required for activation"
111
+ }
112
+ }