intentdna 1.7.0 → 1.7.4

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 (47) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +26 -15
  4. package/dist/cli/commands/feedback.d.ts +2 -2
  5. package/dist/cli/commands/feedback.js +5 -5
  6. package/dist/cli/commands/sync.js +8 -5
  7. package/dist/cli/commands/verify.d.ts +32 -0
  8. package/dist/cli/commands/verify.js +173 -6
  9. package/dist/cli/index.js +3 -1
  10. package/dist/compiler/activate.js +11 -6
  11. package/dist/compiler/cascade.d.ts +3 -1
  12. package/dist/compiler/cascade.js +23 -1
  13. package/dist/compiler/compile.js +1 -0
  14. package/dist/compiler/index.d.ts +5 -1
  15. package/dist/compiler/index.js +7 -4
  16. package/dist/compiler/input-resolver.d.ts +8 -1
  17. package/dist/compiler/input-resolver.js +128 -22
  18. package/dist/compiler/provenance.d.ts +8 -0
  19. package/dist/compiler/provenance.js +127 -0
  20. package/dist/governance/index.d.ts +4 -3
  21. package/dist/governance/index.js +3 -4
  22. package/dist/governance/runtime-decision-event.d.ts +85 -0
  23. package/dist/governance/runtime-decision-event.js +231 -0
  24. package/dist/governance/types.d.ts +3 -3
  25. package/dist/governance/types.js +3 -3
  26. package/dist/hooks/cli.js +162 -13
  27. package/dist/hooks/state.d.ts +3 -10
  28. package/dist/hooks/state.js +147 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +1 -0
  31. package/dist/mcp/tools-observability.js +3 -3
  32. package/dist/mcp/tools-state.d.ts +1 -1
  33. package/dist/mcp/tools-state.js +17 -7
  34. package/dist/report/kernel-report.d.ts +27 -0
  35. package/dist/report/kernel-report.js +60 -19
  36. package/dist/report/kernel-signals.d.ts +5 -2
  37. package/dist/report/kernel-signals.js +84 -2
  38. package/dist/report/report-package.d.ts +9 -1
  39. package/dist/report/report-package.js +32 -27
  40. package/dist/runtime/claude-sdk.d.ts +9 -4
  41. package/dist/runtime/claude-sdk.js +9 -0
  42. package/dist/runtime/plugin-adapter.d.ts +5 -1
  43. package/dist/runtime/plugin-adapter.js +2 -0
  44. package/dist/schema/types.d.ts +51 -0
  45. package/package.json +1 -1
  46. package/spec/README.md +1 -1
  47. package/spec/schema-spec.md +78 -1
@@ -1,9 +1,16 @@
1
1
  import type { DNAWorkflowState, TraceEntry, VerifierResultEntry } from "../hooks/state.js";
2
2
  import type { CompletedArtifactEntry } from "../schema/types.js";
3
+ import { type RuntimeDecisionEvent } from "../governance/index.js";
3
4
  import { type KernelReport, type KernelReportOptions } from "./kernel-report.js";
4
5
  export type EvidenceRef = {
6
+ type: "runtime_decision";
7
+ event_id: string;
8
+ } | {
5
9
  type: "trace";
6
10
  trace_id: string;
11
+ } | {
12
+ type: "audit";
13
+ audit_id: string;
7
14
  } | {
8
15
  type: "verifier_result";
9
16
  result_id: string;
@@ -14,7 +21,7 @@ export type EvidenceRef = {
14
21
  };
15
22
  export interface CriticalDecision {
16
23
  decision_id: string;
17
- kind: "block" | "warn" | "verifier_failure" | "handoff_gate";
24
+ kind: "block" | "warn" | "escalate" | "verifier_failure" | "handoff_gate";
18
25
  summary: string;
19
26
  refs: EvidenceRef[];
20
27
  }
@@ -23,6 +30,7 @@ export interface ReportPackage {
23
30
  generated_at: string;
24
31
  source: KernelReport["source"];
25
32
  kernel_report: KernelReport;
33
+ runtime_decisions: RuntimeDecisionEvent[];
26
34
  traces: TraceEntry[];
27
35
  verifier_results: VerifierResultEntry[];
28
36
  handoffs: {
@@ -1,4 +1,5 @@
1
- import { readTraces, readVerifierResults, readWorkflowState } from "../hooks/state.js";
1
+ import { readRuntimeDecisionEvents, readTraces, readVerifierResults, readWorkflowState } from "../hooks/state.js";
2
+ import { validateRuntimeDecisionEvent } from "../governance/index.js";
2
3
  import { buildKernelReport } from "./kernel-report.js";
3
4
  function withinDays(timestamp, days) {
4
5
  const parsed = Date.parse(timestamp);
@@ -19,34 +20,32 @@ function artifactRefs(completed) {
19
20
  }
20
21
  return refs;
21
22
  }
22
- function buildCriticalDecisions(traces, verifierResults, completed) {
23
+ function refsForRuntimeDecision(event) {
24
+ const refs = [{ type: "runtime_decision", event_id: event.event_id }];
25
+ for (const ref of event.evidence_refs) {
26
+ if (ref.type === "trace")
27
+ refs.push({ type: "trace", trace_id: ref.ref });
28
+ if (ref.type === "audit")
29
+ refs.push({ type: "audit", audit_id: ref.ref });
30
+ if (ref.type === "verifier")
31
+ refs.push({ type: "verifier_result", result_id: ref.ref });
32
+ if (ref.type === "artifact" || ref.type === "handoff")
33
+ refs.push({ type: "artifact", artifact_id: ref.ref });
34
+ }
35
+ return refs;
36
+ }
37
+ function buildCriticalDecisions(runtimeDecisions) {
23
38
  const decisions = [];
24
- for (const trace of traces) {
25
- if (trace.decision !== "block" && trace.decision !== "warn")
39
+ for (const event of runtimeDecisions) {
40
+ if (validateRuntimeDecisionEvent(event).classification !== "enterprise_evidence")
26
41
  continue;
27
- decisions.push({
28
- decision_id: `${trace.decision}:${trace.trace_id}`,
29
- kind: trace.decision,
30
- summary: trace.reason?.split("\n")[0] ?? `${trace.decision} decision`,
31
- refs: [{ type: "trace", trace_id: trace.trace_id }],
32
- });
33
- }
34
- for (const result of verifierResults) {
35
- if (result.status !== "fail")
42
+ if (event.decision !== "block" && event.decision !== "warn" && event.decision !== "escalate")
36
43
  continue;
37
44
  decisions.push({
38
- decision_id: `verifier_failure:${result.result_id ?? result.verifier_id}`,
39
- kind: "verifier_failure",
40
- summary: result.message ?? `Verifier failed: ${result.verifier_id}`,
41
- refs: [{ type: "verifier_result", result_id: result.result_id ?? result.verifier_id }],
42
- });
43
- }
44
- for (const ref of artifactRefs(completed)) {
45
- decisions.push({
46
- decision_id: `handoff_gate:${ref.artifact_id}`,
47
- kind: "handoff_gate",
48
- summary: `Completed handoff artifact ${ref.artifact_id}`,
49
- refs: [{ type: "artifact", artifact_id: ref.artifact_id, path: ref.path }],
45
+ decision_id: `${event.decision}:${event.event_id}`,
46
+ kind: event.decision,
47
+ summary: event.decision_reason.split("\n")[0] || `${event.decision} decision`,
48
+ refs: refsForRuntimeDecision(event),
50
49
  });
51
50
  }
52
51
  return decisions;
@@ -54,6 +53,7 @@ function buildCriticalDecisions(traces, verifierResults, completed) {
54
53
  export async function buildReportPackage(options) {
55
54
  const days = options.days ?? 7;
56
55
  const kernelReport = await buildKernelReport(options);
56
+ const runtimeDecisions = await readRuntimeDecisionEvents(options.projectDir, days, options.sessionId);
57
57
  const traces = await readTraces(options.projectDir, days, options.sessionId);
58
58
  const verifierResults = (await readVerifierResults(options.projectDir, options.sessionId))
59
59
  .filter((result) => withinDays(result.timestamp, days));
@@ -64,6 +64,7 @@ export async function buildReportPackage(options) {
64
64
  generated_at: new Date().toISOString(),
65
65
  source: kernelReport.source,
66
66
  kernel_report: kernelReport,
67
+ runtime_decisions: runtimeDecisions,
67
68
  traces,
68
69
  verifier_results: verifierResults,
69
70
  handoffs: {
@@ -71,9 +72,13 @@ export async function buildReportPackage(options) {
71
72
  completed_artifacts: completedArtifacts,
72
73
  artifact_refs: artifactRefs(completedArtifacts),
73
74
  },
74
- diagnostics: [],
75
+ diagnostics: [
76
+ ...(traces.length > 0 ? [{ severity: "info", code: "legacy_trace_diagnostic", message: `${traces.length} trace record(s) included as diagnostic-only evidence` }] : []),
77
+ ...(verifierResults.length > 0 ? [{ severity: "info", code: "legacy_verifier_diagnostic", message: `${verifierResults.length} verifier result(s) included as diagnostic-only evidence` }] : []),
78
+ ...(completedArtifacts.length > 0 ? [{ severity: "info", code: "workflow_state_diagnostic", message: `${completedArtifacts.length} workflow handoff entry group(s) included as diagnostic-only evidence` }] : []),
79
+ ],
75
80
  deferrals: [],
76
- critical_decisions: buildCriticalDecisions(traces, verifierResults, completedArtifacts),
81
+ critical_decisions: buildCriticalDecisions(runtimeDecisions),
77
82
  mutation: {
78
83
  command_class: options.includeMarkerPreview ? "preview-only" : "read-only",
79
84
  wrote_state: false,
@@ -8,7 +8,7 @@
8
8
  * post_execution_validators → PostToolUse hooks
9
9
  * context_injections → UserPromptSubmit hook
10
10
  */
11
- import type { ConstraintIR } from "../schema/types.js";
11
+ import type { CompiledProvenanceManifest, ConstraintIR, ConstraintProvenance } from "../schema/types.js";
12
12
  export interface DNAHookOutput {
13
13
  hookSpecificOutput?: {
14
14
  hookEventName: string;
@@ -32,19 +32,24 @@ export interface ClaudeDNAConfig {
32
32
  source_dna_ids: string[];
33
33
  /** Compilation timestamp */
34
34
  compiled_at: string;
35
+ /** Stable compiled IR hash for runtime decision events */
36
+ compiled_ir_hash?: string;
37
+ /** Cascade/source provenance for SDK-side checks */
38
+ provenance?: CompiledProvenanceManifest;
35
39
  }
36
40
  export interface PreToolRule {
37
41
  condition: string;
38
42
  action: "block" | "escalate" | "warn";
39
43
  message: string;
40
44
  source_gene: string;
45
+ constraint_provenance?: ConstraintProvenance;
46
+ compiled_ir_hash?: string;
41
47
  }
42
48
  export interface PostToolRule {
43
49
  check: string;
44
50
  threshold?: number;
45
51
  source_gene: string;
52
+ constraint_provenance?: ConstraintProvenance;
53
+ compiled_ir_hash?: string;
46
54
  }
47
- /**
48
- * Compile Constraint IR to Claude Agent SDK configuration.
49
- */
50
55
  export declare function compileForClaude(ir: ConstraintIR): ClaudeDNAConfig;
@@ -12,6 +12,9 @@
12
12
  /**
13
13
  * Compile Constraint IR to Claude Agent SDK configuration.
14
14
  */
15
+ function provenanceForGene(ir, geneId) {
16
+ return ir.provenance?.constraint_winners.find((constraint) => constraint.gene_id === geneId);
17
+ }
15
18
  export function compileForClaude(ir) {
16
19
  // Build system prompt addition from directives
17
20
  const promptLines = [];
@@ -61,11 +64,15 @@ export function compileForClaude(ir) {
61
64
  action: g.action,
62
65
  message: g.message,
63
66
  source_gene: g.source_gene,
67
+ constraint_provenance: provenanceForGene(ir, g.source_gene),
68
+ compiled_ir_hash: ir.compiled_ir_hash,
64
69
  })),
65
70
  post_tool_rules: ir.post_execution_validators.map((v) => ({
66
71
  check: v.check,
67
72
  threshold: v.threshold,
68
73
  source_gene: v.source_gene,
74
+ constraint_provenance: provenanceForGene(ir, v.source_gene),
75
+ compiled_ir_hash: ir.compiled_ir_hash,
69
76
  })),
70
77
  context_additions: ir.context_injections.map((c) => c.text),
71
78
  deprioritized_tools: ir.tool_filters
@@ -73,5 +80,7 @@ export function compileForClaude(ir) {
73
80
  .map((f) => f.target),
74
81
  source_dna_ids: ir.source_dna_ids,
75
82
  compiled_at: ir.compiled_at,
83
+ compiled_ir_hash: ir.compiled_ir_hash,
84
+ provenance: ir.provenance,
76
85
  };
77
86
  }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * This is the bridge between compile-time (dna sync) and runtime (hook execution).
8
8
  */
9
- import type { ConstraintIR, RoleDef } from "../schema/types.js";
9
+ import type { CompiledProvenanceManifest, ConstraintIR, RoleDef } from "../schema/types.js";
10
10
  /** Wrapper around ConstraintIR with versioning metadata */
11
11
  export interface CompiledIRFile {
12
12
  /** Schema version for forward compatibility */
@@ -19,6 +19,10 @@ export interface CompiledIRFile {
19
19
  ir: ConstraintIR;
20
20
  /** Cascaded role definitions (for output_schema enforcement) */
21
21
  roles?: Record<string, RoleDef>;
22
+ /** Stable hash of the compiled IR payload, excluding provenance/hash fields */
23
+ compiled_ir_hash?: string;
24
+ /** Cascade and source provenance used by enterprise evidence */
25
+ provenance?: CompiledProvenanceManifest;
22
26
  }
23
27
  /**
24
28
  * Create a CompiledIRFile wrapper around a ConstraintIR.
@@ -20,6 +20,8 @@ export function createCompiledIR(ir, roles) {
20
20
  source_dna_ids: ir.source_dna_ids,
21
21
  ir,
22
22
  roles: roles && Object.keys(roles).length > 0 ? roles : undefined,
23
+ compiled_ir_hash: ir.compiled_ir_hash,
24
+ provenance: ir.provenance,
23
25
  };
24
26
  }
25
27
  /**
@@ -17,9 +17,16 @@ export interface RepelCodon {
17
17
  type: "repel";
18
18
  target: string;
19
19
  }
20
+ export interface ConstraintOrigin {
21
+ source_dna_id: string;
22
+ source_layer: DNAType;
23
+ cascade_priority: number;
24
+ protected_threshold?: boolean;
25
+ }
20
26
  export interface ThresholdCodon {
21
27
  type: "threshold";
22
28
  condition: string;
29
+ origin?: ConstraintOrigin;
23
30
  }
24
31
  export interface WeightCodon {
25
32
  type: "weight";
@@ -262,6 +269,47 @@ export interface CascadeConfig {
262
269
  inherits: string[];
263
270
  priority: number;
264
271
  }
272
+ export type ProvenanceCascadeLayerName = "species" | "enterprise" | "project" | "personal" | "role" | "context" | "task";
273
+ export type ProvenanceLayerStatus = "active" | "unknown" | "unsupported";
274
+ export type ProvenanceSourceTrust = "builtin" | "admin_shared" | "project_local" | "user_local" | "explicit_file" | "input";
275
+ export interface DNASourceProvenance {
276
+ source_id: string;
277
+ source_ref: string;
278
+ resolved_path: string;
279
+ fingerprint: string;
280
+ type: DNAType;
281
+ cascade_priority: number;
282
+ version: string;
283
+ trust: ProvenanceSourceTrust;
284
+ inherited_by?: string;
285
+ genes?: string[];
286
+ }
287
+ export interface CascadeLayerProvenance {
288
+ layer: ProvenanceCascadeLayerName;
289
+ source_id: string;
290
+ source_ref: string;
291
+ fingerprint: string;
292
+ status: ProvenanceLayerStatus;
293
+ sources?: string[];
294
+ }
295
+ export interface ConstraintProvenance {
296
+ constraint_id: string;
297
+ source_layer: ProvenanceCascadeLayerName | "unknown" | "unsupported";
298
+ source_dna_id: string;
299
+ gene_id: string;
300
+ codon_type: CodonType | "unknown";
301
+ action: "allow" | "warn" | "block" | "escalate" | "validate";
302
+ provenance_reason: string;
303
+ }
304
+ export interface CompiledProvenanceManifest {
305
+ schema_version: "intentdna.provenance.v1.7.2";
306
+ policy_bundle_id: string;
307
+ policy_bundle_version: string;
308
+ sources: DNASourceProvenance[];
309
+ cascade_layers: Record<ProvenanceCascadeLayerName, CascadeLayerProvenance>;
310
+ constraint_winners: ConstraintProvenance[];
311
+ compiled_ir_hash: string;
312
+ }
265
313
  export interface VariableDef {
266
314
  description: string;
267
315
  default: string;
@@ -372,6 +420,7 @@ export interface PreExecutionGate {
372
420
  action: "block" | "escalate" | "warn";
373
421
  message: string;
374
422
  source_gene: string;
423
+ origin?: ConstraintOrigin;
375
424
  }
376
425
  export interface PostExecutionValidator {
377
426
  check: string;
@@ -488,6 +537,8 @@ export interface ConstraintIR {
488
537
  per_workflow?: Record<string, string[]>;
489
538
  };
490
539
  verifier_policy?: VerifierCommandPolicy;
540
+ provenance?: CompiledProvenanceManifest;
541
+ compiled_ir_hash?: string;
491
542
  }
492
543
  /** A compiled workflow step with resolved metadata */
493
544
  export interface WorkflowStep {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intentdna",
3
- "version": "1.7.0",
3
+ "version": "1.7.4",
4
4
  "description": "Intent DNA — Declarative policy layer for AI agent behavior",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/spec/README.md CHANGED
@@ -15,7 +15,7 @@ This directory contains engineering specs. Use [ROADMAP.md](../ROADMAP.md) as th
15
15
 
16
16
  | Spec | Status | Purpose |
17
17
  |------|--------|---------|
18
- | [schema-spec.md](schema-spec.md) | Canonical | Intent DNA document structure, genes, roles, workflows, cascade, and IR contract. |
18
+ | [schema-spec.md](schema-spec.md) | Canonical | Intent DNA document structure, genes, roles, workflows, cascade, Enterprise bundle inheritance, RuntimeDecisionEvent, and IR contract. |
19
19
  | [foundation-hardening.md](foundation-hardening.md) | Active reference | Reliability, governance, MCP, and tool-experience hardening plan. |
20
20
  | [hooks-infra-harness-hardening.md](hooks-infra-harness-hardening.md) | Active reference | Hook boundary schema, enforcement result types, state manager, context/reflection/workflow gates. |
21
21
  | [workflow-pipeline.md](workflow-pipeline.md) | Active reference | Workflow pipeline design and state management unification. |
@@ -386,7 +386,7 @@ Or shorthand: `max_rounds: 3` (equivalent to max_retries: 2)
386
386
 
387
387
  ## Cascade (Inheritance)
388
388
 
389
- DNA configs inherit from parent layers using CSS-like cascade.
389
+ DNA configs inherit from parent layers using CSS-like cascade. The enterprise safety cascade order is Species → Enterprise → Project → Personal → Role → Context → Task.
390
390
 
391
391
  ```yaml
392
392
  cascade:
@@ -404,6 +404,83 @@ cascade:
404
404
  ### Threshold Protection
405
405
  Threshold codons from lower-priority layers **cannot be removed** by higher-priority layers. This ensures safety invariants propagate up the chain.
406
406
 
407
+ Species and Enterprise thresholds are organization red lines. Project, Personal, Role, Context, and Task layers may add stricter thresholds, but they cannot relax, remove, bypass, or downgrade Species/Enterprise thresholds.
408
+
409
+ ### Enterprise Bundle Inheritance (v1.7.x local/shared slice)
410
+
411
+ The v1.7.x Enterprise Safety Slice is scoped to local and shared policy bundle references only; it does not implement remote registry, signing, push/pull, or SaaS permissions. In v1.7.1 this section freezes the contract and resolver boundary; the concrete `dna sync` / `dna verify` resolver implementation is planned for v1.7.2.
412
+
413
+ Candidate bundle locations:
414
+
415
+ - `INTENTDNA_ENTERPRISE_POLICY_DIR` — admin/team-controlled shared root for authoritative local dogfood
416
+ - `.dna/policies/enterprise/*.dna.yaml` — project-local bundle for development and fixture use
417
+ - `~/.intentdna/policies/enterprise/*.dna.yaml` — user-local bundle for development and personal dogfood
418
+ - `test/fixtures/enterprise-policies/` — test-only fixture root
419
+
420
+ Project-local and user-local bundles are not organization-authoritative by themselves. They must be treated as local/dev provenance unless the future v1.7.2 resolver can tie them to an admin-controlled root or pinned fingerprint.
421
+
422
+ Supported reference forms:
423
+
424
+ ```yaml
425
+ cascade:
426
+ inherits:
427
+ - "enterprise:baseline" # resolves baseline.dna.yaml from candidate dirs
428
+ - "file:../shared/baseline.dna.yaml" # explicit local/shared file
429
+ ```
430
+
431
+ For v1.7.2, `dna sync` must materialize the resolved bundle id/version, source path, fingerprint, cascade layer fingerprints, and compiled IR hash into provenance. `dna verify` must reject unresolved references, inheritance cycles, missing bundle metadata, and attempts by lower layers to relax Species/Enterprise thresholds.
432
+
433
+ ---
434
+
435
+ ## Enterprise Provenance Contract (v1.7.1)
436
+
437
+ v1.7.1 freezes the enterprise evidence contract before the full implementation lands. `RuntimeDecisionEvent` is required for enterprise governance evidence; legacy trace/audit/state records without this provenance remain diagnostic only.
438
+
439
+ ### PolicyBundle
440
+
441
+ A policy bundle records the policy source that produced enforcement-relevant constraints:
442
+
443
+ | Field | Required | Description |
444
+ |-------|----------|-------------|
445
+ | `policy_bundle_id` | yes | Stable bundle id, e.g. `enterprise_baseline` |
446
+ | `policy_bundle_version` | yes | Bundle version used for the decision |
447
+ | `source_ref` | yes | `enterprise:baseline`, `file:...`, or a local source path |
448
+ | `fingerprint` | yes | Stable content/source fingerprint |
449
+
450
+ ### CascadeLayerFingerprint
451
+
452
+ `cascade_layers` must include every layer: `species`, `enterprise`, `project`, `personal`, `role`, `context`, and `task`.
453
+
454
+ | Field | Required | Description |
455
+ |-------|----------|-------------|
456
+ | `layer` | yes | One of the fixed cascade layer names |
457
+ | `source_id` | yes | DNA or placeholder source id |
458
+ | `source_ref` | yes | Resolved source path/reference or `unknown` / `unsupported` |
459
+ | `fingerprint` | yes | Layer fingerprint or `unknown` / `unsupported` |
460
+ | `status` | yes | `active`, `unknown`, or `unsupported` |
461
+
462
+ ### RuntimeDecisionEvent
463
+
464
+ Every enterprise runtime decision must include these required fields:
465
+
466
+ ```text
467
+ schema_version, event_id, timestamp,
468
+ org_id, team_id, user_id, project_id,
469
+ agent_id, agent_role, agent_type, session_agent,
470
+ harness_adapter, runtime,
471
+ policy_bundle_id, policy_bundle_version,
472
+ cascade_layers, winning_constraint, compiled_ir_hash,
473
+ decision, decision_reason,
474
+ enforcement_point, harness_runtime_context,
475
+ session_id, run_id, step_id,
476
+ tool_name, action_kind, resource_ref,
477
+ evidence_refs
478
+ ```
479
+
480
+ `decision` is one of `allow`, `warn`, `block`, `escalate`, or `validate`. `enforcement_point` is one of `hook`, `sdk`, `ci`, `plugin_runtime`, `mcp_external_write`, `unknown`, or `unsupported`.
481
+
482
+ The first implementation may fill unavailable dimensions with explicit `unknown` or `unsupported` values, but it must not omit required fields. Placeholder values make the event syntactically valid for phased rollout, not enterprise-authoritative: any required provenance field that remains `unknown` / `unsupported`, or any `legacy` / placeholder `evidence_refs` entry, keeps the event classified as `legacy_diagnostic`. Events missing required fields or classified as diagnostic cannot enter enterprise compliance statistics. MCP, reports, dashboards, and evolution consume this event as evidence; they do not create policy truth.
483
+
407
484
  ---
408
485
 
409
486
  ## Variables