@neurcode-ai/cli 0.10.1 → 0.14.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 (199) hide show
  1. package/.telemetry-bundle/dist/contracts.d.ts +1 -1
  2. package/README.md +74 -25
  3. package/dist/commands/governance.d.ts.map +1 -1
  4. package/dist/commands/governance.js +12 -0
  5. package/dist/commands/governance.js.map +1 -1
  6. package/dist/commands/home.d.ts +21 -0
  7. package/dist/commands/home.d.ts.map +1 -0
  8. package/dist/commands/home.js +253 -0
  9. package/dist/commands/home.js.map +1 -0
  10. package/dist/commands/login.js +1 -1
  11. package/dist/commands/login.js.map +1 -1
  12. package/dist/commands/quickstart.d.ts.map +1 -1
  13. package/dist/commands/quickstart.js +13 -11
  14. package/dist/commands/quickstart.js.map +1 -1
  15. package/dist/commands/remediate-export.d.ts.map +1 -1
  16. package/dist/commands/remediate-export.js +17 -2
  17. package/dist/commands/remediate-export.js.map +1 -1
  18. package/dist/commands/replay.d.ts.map +1 -1
  19. package/dist/commands/replay.js +36 -0
  20. package/dist/commands/replay.js.map +1 -1
  21. package/dist/commands/verify-output.d.ts.map +1 -1
  22. package/dist/commands/verify-output.js +88 -4
  23. package/dist/commands/verify-output.js.map +1 -1
  24. package/dist/commands/verify.d.ts +22 -1
  25. package/dist/commands/verify.d.ts.map +1 -1
  26. package/dist/commands/verify.js +467 -37
  27. package/dist/commands/verify.js.map +1 -1
  28. package/dist/daemon/server.d.ts.map +1 -1
  29. package/dist/daemon/server.js +4 -0
  30. package/dist/daemon/server.js.map +1 -1
  31. package/dist/governance/canonical-pipeline.d.ts.map +1 -1
  32. package/dist/governance/canonical-pipeline.js +29 -3
  33. package/dist/governance/canonical-pipeline.js.map +1 -1
  34. package/dist/governance/intent/drift-detector.d.ts +100 -0
  35. package/dist/governance/intent/drift-detector.d.ts.map +1 -0
  36. package/dist/governance/intent/drift-detector.js +275 -0
  37. package/dist/governance/intent/drift-detector.js.map +1 -0
  38. package/dist/governance/intent/glob-match.d.ts +43 -0
  39. package/dist/governance/intent/glob-match.d.ts.map +1 -0
  40. package/dist/governance/intent/glob-match.js +108 -0
  41. package/dist/governance/intent/glob-match.js.map +1 -0
  42. package/dist/governance/intent/import-graph.d.ts +56 -0
  43. package/dist/governance/intent/import-graph.d.ts.map +1 -0
  44. package/dist/governance/intent/import-graph.js +133 -0
  45. package/dist/governance/intent/import-graph.js.map +1 -0
  46. package/dist/governance/intent/index.d.ts +23 -0
  47. package/dist/governance/intent/index.d.ts.map +1 -0
  48. package/dist/governance/intent/index.js +48 -0
  49. package/dist/governance/intent/index.js.map +1 -0
  50. package/dist/governance/intent/intelligence-boundaries.d.ts +69 -0
  51. package/dist/governance/intent/intelligence-boundaries.d.ts.map +1 -0
  52. package/dist/governance/intent/intelligence-boundaries.js +163 -0
  53. package/dist/governance/intent/intelligence-boundaries.js.map +1 -0
  54. package/dist/governance/intent/intent-contract.d.ts +76 -0
  55. package/dist/governance/intent/intent-contract.d.ts.map +1 -0
  56. package/dist/governance/intent/intent-contract.js +397 -0
  57. package/dist/governance/intent/intent-contract.js.map +1 -0
  58. package/dist/governance/intent/intent-graph.d.ts +135 -0
  59. package/dist/governance/intent/intent-graph.d.ts.map +1 -0
  60. package/dist/governance/intent/intent-graph.js +67 -0
  61. package/dist/governance/intent/intent-graph.js.map +1 -0
  62. package/dist/governance/pipeline/computation-trace.d.ts +52 -0
  63. package/dist/governance/pipeline/computation-trace.d.ts.map +1 -0
  64. package/dist/governance/pipeline/computation-trace.js +79 -0
  65. package/dist/governance/pipeline/computation-trace.js.map +1 -0
  66. package/dist/governance/pipeline/envelope-assembly.d.ts +132 -0
  67. package/dist/governance/pipeline/envelope-assembly.d.ts.map +1 -0
  68. package/dist/governance/pipeline/envelope-assembly.js +140 -0
  69. package/dist/governance/pipeline/envelope-assembly.js.map +1 -0
  70. package/dist/governance/pipeline/fingerprint.d.ts +34 -0
  71. package/dist/governance/pipeline/fingerprint.d.ts.map +1 -0
  72. package/dist/governance/pipeline/fingerprint.js +78 -0
  73. package/dist/governance/pipeline/fingerprint.js.map +1 -0
  74. package/dist/governance/pipeline/helpers.d.ts +74 -0
  75. package/dist/governance/pipeline/helpers.d.ts.map +1 -0
  76. package/dist/governance/pipeline/helpers.js +112 -0
  77. package/dist/governance/pipeline/helpers.js.map +1 -0
  78. package/dist/governance/pipeline/index.d.ts +27 -0
  79. package/dist/governance/pipeline/index.d.ts.map +1 -0
  80. package/dist/governance/pipeline/index.js +63 -0
  81. package/dist/governance/pipeline/index.js.map +1 -0
  82. package/dist/governance/pipeline/lineage.d.ts +26 -0
  83. package/dist/governance/pipeline/lineage.d.ts.map +1 -0
  84. package/dist/governance/pipeline/lineage.js +51 -0
  85. package/dist/governance/pipeline/lineage.js.map +1 -0
  86. package/dist/governance/pipeline/orchestration/advisory-mode-contract.d.ts +15 -0
  87. package/dist/governance/pipeline/orchestration/advisory-mode-contract.d.ts.map +1 -0
  88. package/dist/governance/pipeline/orchestration/advisory-mode-contract.js +44 -0
  89. package/dist/governance/pipeline/orchestration/advisory-mode-contract.js.map +1 -0
  90. package/dist/governance/pipeline/orchestration/advisory-mode.d.ts +102 -0
  91. package/dist/governance/pipeline/orchestration/advisory-mode.d.ts.map +1 -0
  92. package/dist/governance/pipeline/orchestration/advisory-mode.js +170 -0
  93. package/dist/governance/pipeline/orchestration/advisory-mode.js.map +1 -0
  94. package/dist/governance/pipeline/orchestration/evidence-lifecycle.d.ts +133 -0
  95. package/dist/governance/pipeline/orchestration/evidence-lifecycle.d.ts.map +1 -0
  96. package/dist/governance/pipeline/orchestration/evidence-lifecycle.js +125 -0
  97. package/dist/governance/pipeline/orchestration/evidence-lifecycle.js.map +1 -0
  98. package/dist/governance/pipeline/orchestration/index.d.ts +16 -0
  99. package/dist/governance/pipeline/orchestration/index.d.ts.map +1 -0
  100. package/dist/governance/pipeline/orchestration/index.js +30 -0
  101. package/dist/governance/pipeline/orchestration/index.js.map +1 -0
  102. package/dist/governance/pipeline/orchestration/intent-drift-orchestration.d.ts +65 -0
  103. package/dist/governance/pipeline/orchestration/intent-drift-orchestration.d.ts.map +1 -0
  104. package/dist/governance/pipeline/orchestration/intent-drift-orchestration.js +102 -0
  105. package/dist/governance/pipeline/orchestration/intent-drift-orchestration.js.map +1 -0
  106. package/dist/governance/pipeline/orchestration/plan-structural-analysis.d.ts +41 -0
  107. package/dist/governance/pipeline/orchestration/plan-structural-analysis.d.ts.map +1 -0
  108. package/dist/governance/pipeline/orchestration/plan-structural-analysis.js +74 -0
  109. package/dist/governance/pipeline/orchestration/plan-structural-analysis.js.map +1 -0
  110. package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.d.ts +165 -0
  111. package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.d.ts.map +1 -0
  112. package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.js +160 -0
  113. package/dist/governance/pipeline/orchestration/policy-evaluation-summaries.js.map +1 -0
  114. package/dist/governance/pipeline/orchestration/scope-guard-orchestration.d.ts +152 -0
  115. package/dist/governance/pipeline/orchestration/scope-guard-orchestration.d.ts.map +1 -0
  116. package/dist/governance/pipeline/orchestration/scope-guard-orchestration.js +188 -0
  117. package/dist/governance/pipeline/orchestration/scope-guard-orchestration.js.map +1 -0
  118. package/dist/governance/pipeline/runtime.d.ts +70 -0
  119. package/dist/governance/pipeline/runtime.d.ts.map +1 -0
  120. package/dist/governance/pipeline/runtime.js +223 -0
  121. package/dist/governance/pipeline/runtime.js.map +1 -0
  122. package/dist/governance/pipeline/shared-types.d.ts +7 -0
  123. package/dist/governance/pipeline/shared-types.d.ts.map +1 -0
  124. package/dist/governance/pipeline/shared-types.js +7 -0
  125. package/dist/governance/pipeline/shared-types.js.map +1 -0
  126. package/dist/governance/pipeline/stages/compiled-policy-stage.d.ts +28 -0
  127. package/dist/governance/pipeline/stages/compiled-policy-stage.d.ts.map +1 -0
  128. package/dist/governance/pipeline/stages/compiled-policy-stage.js +53 -0
  129. package/dist/governance/pipeline/stages/compiled-policy-stage.js.map +1 -0
  130. package/dist/governance/pipeline/stages/diff-normalization-stage.d.ts +63 -0
  131. package/dist/governance/pipeline/stages/diff-normalization-stage.d.ts.map +1 -0
  132. package/dist/governance/pipeline/stages/diff-normalization-stage.js +140 -0
  133. package/dist/governance/pipeline/stages/diff-normalization-stage.js.map +1 -0
  134. package/dist/governance/pipeline/stages/governance-synthesis-stage.d.ts +53 -0
  135. package/dist/governance/pipeline/stages/governance-synthesis-stage.d.ts.map +1 -0
  136. package/dist/governance/pipeline/stages/governance-synthesis-stage.js +129 -0
  137. package/dist/governance/pipeline/stages/governance-synthesis-stage.js.map +1 -0
  138. package/dist/governance/pipeline/stages/index.d.ts +29 -0
  139. package/dist/governance/pipeline/stages/index.d.ts.map +1 -0
  140. package/dist/governance/pipeline/stages/index.js +40 -0
  141. package/dist/governance/pipeline/stages/index.js.map +1 -0
  142. package/dist/governance/pipeline/stages/policy-lock-stage.d.ts +31 -0
  143. package/dist/governance/pipeline/stages/policy-lock-stage.d.ts.map +1 -0
  144. package/dist/governance/pipeline/stages/policy-lock-stage.js +71 -0
  145. package/dist/governance/pipeline/stages/policy-lock-stage.js.map +1 -0
  146. package/dist/governance/pipeline/stages/runtime-guard-stage.d.ts +29 -0
  147. package/dist/governance/pipeline/stages/runtime-guard-stage.d.ts.map +1 -0
  148. package/dist/governance/pipeline/stages/runtime-guard-stage.js +65 -0
  149. package/dist/governance/pipeline/stages/runtime-guard-stage.js.map +1 -0
  150. package/dist/governance/pipeline/stages/structural-analysis-stage.d.ts +24 -0
  151. package/dist/governance/pipeline/stages/structural-analysis-stage.d.ts.map +1 -0
  152. package/dist/governance/pipeline/stages/structural-analysis-stage.js +58 -0
  153. package/dist/governance/pipeline/stages/structural-analysis-stage.js.map +1 -0
  154. package/dist/governance/pipeline/summary.d.ts +14 -0
  155. package/dist/governance/pipeline/summary.d.ts.map +1 -0
  156. package/dist/governance/pipeline/summary.js +50 -0
  157. package/dist/governance/pipeline/summary.js.map +1 -0
  158. package/dist/governance/pipeline/types.d.ts +69 -0
  159. package/dist/governance/pipeline/types.d.ts.map +1 -0
  160. package/dist/governance/pipeline/types.js +30 -0
  161. package/dist/governance/pipeline/types.js.map +1 -0
  162. package/dist/index.js +44 -3
  163. package/dist/index.js.map +1 -1
  164. package/dist/utils/active-engineering-context.d.ts +16 -0
  165. package/dist/utils/active-engineering-context.d.ts.map +1 -1
  166. package/dist/utils/active-engineering-context.js +302 -0
  167. package/dist/utils/active-engineering-context.js.map +1 -1
  168. package/dist/utils/import-edge-classifier.d.ts +76 -0
  169. package/dist/utils/import-edge-classifier.d.ts.map +1 -0
  170. package/dist/utils/import-edge-classifier.js +308 -0
  171. package/dist/utils/import-edge-classifier.js.map +1 -0
  172. package/dist/utils/import-edge-extractor.d.ts +52 -0
  173. package/dist/utils/import-edge-extractor.d.ts.map +1 -0
  174. package/dist/utils/import-edge-extractor.js +223 -0
  175. package/dist/utils/import-edge-extractor.js.map +1 -0
  176. package/dist/utils/import-edge-governance.d.ts +37 -0
  177. package/dist/utils/import-edge-governance.d.ts.map +1 -0
  178. package/dist/utils/import-edge-governance.js +56 -0
  179. package/dist/utils/import-edge-governance.js.map +1 -0
  180. package/dist/utils/messages.d.ts.map +1 -1
  181. package/dist/utils/messages.js +19 -10
  182. package/dist/utils/messages.js.map +1 -1
  183. package/dist/utils/path-boundary-classifier.d.ts +42 -0
  184. package/dist/utils/path-boundary-classifier.d.ts.map +1 -0
  185. package/dist/utils/path-boundary-classifier.js +143 -0
  186. package/dist/utils/path-boundary-classifier.js.map +1 -0
  187. package/dist/utils/replay-html-report.d.ts +29 -0
  188. package/dist/utils/replay-html-report.d.ts.map +1 -0
  189. package/dist/utils/replay-html-report.js +309 -0
  190. package/dist/utils/replay-html-report.js.map +1 -0
  191. package/dist/utils/runtime-state.d.ts +44 -0
  192. package/dist/utils/runtime-state.d.ts.map +1 -0
  193. package/dist/utils/runtime-state.js +151 -0
  194. package/dist/utils/runtime-state.js.map +1 -0
  195. package/package.json +3 -3
  196. package/dist/utils/box.d.ts +0 -16
  197. package/dist/utils/box.d.ts.map +0 -1
  198. package/dist/utils/box.js +0 -85
  199. package/dist/utils/box.js.map +0 -1
@@ -2,7 +2,20 @@
2
2
  /**
3
3
  * Verify Command
4
4
  *
5
- * Compares current work (git diff) against an Architect Plan to measure adherence and detect bloat.
5
+ * Runs deterministic operational governance against the current diff:
6
+ * - Intent contract enforcement (approved scope + forbidden boundaries)
7
+ * - Structural rules (PY/SR/DS catalogues)
8
+ * - Drift narrative synthesis + governance posture rollup
9
+ * - Generated-code spillover + boundary classification
10
+ * - Replay continuity (canonical replay checksum, byte-stable per inputs)
11
+ *
12
+ * Emits a single canonical envelope plus a `runtimeCapabilities` declaration so
13
+ * enterprise CI gates can assert what actually executed instead of inferring
14
+ * from absent fields. The command is the verification step in the canonical
15
+ * governance lifecycle; remediation is performed by an external AI assistant,
16
+ * never by this command.
17
+ *
18
+ * See `docs/governance-vocabulary.md` for canonical terminology.
6
19
  */
7
20
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
21
  if (k2 === undefined) k2 = k;
@@ -52,6 +65,7 @@ const fs_1 = require("fs");
52
65
  const state_1 = require("../utils/state");
53
66
  const ROILogger_1 = require("../utils/ROILogger");
54
67
  const ignore_1 = require("../utils/ignore");
68
+ const runtime_state_1 = require("../utils/runtime-state");
55
69
  const project_root_1 = require("../utils/project-root");
56
70
  const brain_context_1 = require("../utils/brain-context");
57
71
  const scope_telemetry_1 = require("../utils/scope-telemetry");
@@ -85,6 +99,9 @@ const runtime_guard_1 = require("../utils/runtime-guard");
85
99
  const artifact_signature_1 = require("../utils/artifact-signature");
86
100
  const policy_1 = require("@neurcode-ai/policy");
87
101
  const active_engineering_context_1 = require("../utils/active-engineering-context");
102
+ const core_1 = require("@neurcode-ai/core");
103
+ const path_boundary_classifier_1 = require("../utils/path-boundary-classifier");
104
+ const import_edge_governance_1 = require("../utils/import-edge-governance");
88
105
  const ai_debt_budget_1 = require("../utils/ai-debt-budget");
89
106
  const verification_evidence_1 = require("../utils/verification-evidence");
90
107
  const verify_runtime_stability_1 = require("../utils/verify-runtime-stability");
@@ -1715,6 +1732,20 @@ async function verifyCommand(options) {
1715
1732
  console.log(chalk.yellow(`\n⚠️ Failed to write verification evidence artifact: ${message}`));
1716
1733
  }
1717
1734
  }
1735
+ // Mirror the canonical envelope into `.neurcode/last-verify-output.json`
1736
+ // so downstream commands (`remediate-export`, `replay --html`) can pick
1737
+ // up the latest run without the user threading paths through stdout
1738
+ // redirection. Closes deep-OSS validation §5.8.
1739
+ try {
1740
+ if (lastCanonicalOutput) {
1741
+ const verifyOutputPath = require('path').resolve(projectRoot, '.neurcode/last-verify-output.json');
1742
+ require('fs').mkdirSync(require('path').dirname(verifyOutputPath), { recursive: true });
1743
+ require('fs').writeFileSync(verifyOutputPath, `${JSON.stringify(lastCanonicalOutput, null, 2)}\n`, 'utf-8');
1744
+ }
1745
+ }
1746
+ catch {
1747
+ // Persisting the canonical output is best-effort; never block exit.
1748
+ }
1718
1749
  };
1719
1750
  const exitWithEvidence = (exitCode) => {
1720
1751
  finalizeEvidence(exitCode);
@@ -2286,6 +2317,17 @@ async function verifyCommand(options) {
2286
2317
  // Determine which diff to capture.
2287
2318
  let diffText;
2288
2319
  let diffContextLabel = '';
2320
+ // Operational lifecycle guardrail: when the diff context requires a
2321
+ // HEAD reference but the repo has no initial commit yet, surface
2322
+ // structured guidance instead of leaking raw git stderr. (See
2323
+ // docs/ux/lifecycle-state-audit.md §"no-head-commit".)
2324
+ if (options.head || options.staged || !options.base) {
2325
+ const lifecycleState = (0, runtime_state_1.detectRuntimeState)(projectRoot);
2326
+ if (lifecycleState.isGitRepo && !lifecycleState.hasHeadCommit) {
2327
+ const exitCode = (0, runtime_state_1.renderRuntimeStateGuidance)('no-head-commit', lifecycleState, { commandLabel: 'neurcode verify' });
2328
+ process.exit(exitCode);
2329
+ }
2330
+ }
2289
2331
  if (options.staged) {
2290
2332
  diffText = (0, child_process_1.execSync)('git diff --cached', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
2291
2333
  diffContextLabel = 'staged changes';
@@ -2323,6 +2365,11 @@ async function verifyCommand(options) {
2323
2365
  console.log(chalk.dim(' Tip: Ensure changes are staged or run against a base branch.'));
2324
2366
  }
2325
2367
  else {
2368
+ // Surface runtime capabilities even on the empty-diff path so
2369
+ // CI gates that assert `runtimeCapabilities.intentRuntime` etc.
2370
+ // never receive a payload that omits the envelope. The intent
2371
+ // runtime is reported as `inactive` here regardless of whether
2372
+ // an intent-pack exists — there are no findings to govern.
2326
2373
  emitVerifyJson({
2327
2374
  grade: 'F',
2328
2375
  score: 0,
@@ -2335,6 +2382,24 @@ async function verifyCommand(options) {
2335
2382
  totalPlannedFiles: 0,
2336
2383
  message: 'No changes detected in current diff context.',
2337
2384
  scopeGuardPassed: false,
2385
+ runtimeCapabilities: {
2386
+ schemaVersion: 'neurcode.runtime-capabilities.v1',
2387
+ executionPath: localOnlyMode ? 'local-only' : 'unresolved',
2388
+ intentRuntime: 'inactive',
2389
+ intentContractSource: 'none',
2390
+ intentRuntimeRequired: options.requireIntentRuntime === true || isEnabledFlag(process.env.NEURCODE_REQUIRE_INTENT_RUNTIME),
2391
+ intentRuntimeRequirementSatisfied: true,
2392
+ driftIntelligence: 'inactive',
2393
+ scopeGuard: 'unenforced',
2394
+ forbiddenBoundaryEnforcement: 'unenforced',
2395
+ generatedCodeGovernance: 'pattern-deterministic',
2396
+ structuralRules: 'inactive',
2397
+ replayDeterminism: 'enforced',
2398
+ apiContractStatus: localOnlyMode ? 'offline' : 'unresolved',
2399
+ observedScopeCategories: [],
2400
+ observedBoundaryTypes: [],
2401
+ noChangesDetected: true,
2402
+ },
2338
2403
  });
2339
2404
  }
2340
2405
  recordVerifyEvent('NO_CHANGES', 'diff=empty');
@@ -2353,11 +2418,17 @@ async function verifyCommand(options) {
2353
2418
  }
2354
2419
  }
2355
2420
  // Filter out internal/system files before analysis
2356
- // This prevents self-interference where the tool flags its own files as bloat
2421
+ // This prevents self-interference where the tool flags its own files as bloat.
2422
+ // Two layers:
2423
+ // 1. `isExcludedFile` — built-in policy/governance artifact patterns
2424
+ // 2. `.neurcodeignore` — per-repo user patterns (closes dogfooding gap
2425
+ // where OSS-clone working trees and scratch dirs were showing up as
2426
+ // out-of-scope noise in self-governance runs)
2427
+ const ignoreFilterAllPaths = (0, ignore_1.loadIgnore)(projectRoot);
2357
2428
  const diffFiles = allDiffFiles.filter(file => {
2358
2429
  // Check both path and oldPath (for renames) against exclusion list
2359
- const excludePath = isExcludedFile(file.path);
2360
- const excludeOldPath = file.oldPath ? isExcludedFile(file.oldPath) : false;
2430
+ const excludePath = isExcludedFile(file.path) || ignoreFilterAllPaths(file.path);
2431
+ const excludeOldPath = file.oldPath ? (isExcludedFile(file.oldPath) || ignoreFilterAllPaths(file.oldPath)) : false;
2361
2432
  return !excludePath && !excludeOldPath;
2362
2433
  });
2363
2434
  // ── Local-only mode (Part 8): run structural analysis and exit, no API calls ──
@@ -2365,54 +2436,381 @@ async function verifyCommand(options) {
2365
2436
  // Deterministic structural governance MUST work offline, with zero API dependency.
2366
2437
  if (localOnlyMode) {
2367
2438
  if (!options.json) {
2368
- console.log(chalk.cyan('\n🔍 Local-only mode: deterministic structural verification (no API required)...'));
2439
+ console.log(chalk.cyan('\n🔍 Local-only mode: deterministic intent-runtime verification (no API required)...'));
2369
2440
  }
2370
2441
  const localStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFiles);
2371
2442
  const localStructuralFindings = localStructural.violations.map(canonical_pipeline_1.findingFromStructural);
2372
- const localReplayChecksum = (0, canonical_invariants_1.computeCanonicalFindingChecksum)(localStructuralFindings);
2373
2443
  const blockingViolations = localStructural.violations.filter((v) => v.severity === 'BLOCKING');
2374
2444
  const advisoryViolations = localStructural.violations.filter((v) => v.severity !== 'BLOCKING');
2375
- const localVerdict = blockingViolations.length > 0 ? 'FAIL' : 'PASS';
2376
- const localGrade = blockingViolations.length > 0 ? 'F' : 'B';
2377
- const localScore = blockingViolations.length > 0 ? 0 : 70;
2445
+ // ─── Intent-runtime activation (deterministic, offline) ──────────────────
2446
+ // When an intent-pack is present in `.neurcode/intent-pack.json` the local
2447
+ // verify path now activates the full governance runtime: scope checks,
2448
+ // forbidden-boundary enforcement, drift narratives and posture synthesis.
2449
+ // Companion artefacts (context-pack, repository-graph, session-runtime)
2450
+ // are deterministically synthesised when they are absent so the runtime
2451
+ // does NOT silently collapse into structural-only mode.
2452
+ let localActiveContext = null;
2453
+ let localGovernanceResult = null;
2454
+ const localScopeIssues = [];
2455
+ let localImportEdgeResult = null;
2456
+ try {
2457
+ localActiveContext = (0, active_engineering_context_1.loadOrSynthesizeEngineeringContext)(projectRoot);
2458
+ }
2459
+ catch (err) {
2460
+ if (!options.json && (process.env.DEBUG || process.env.VERBOSE)) {
2461
+ console.log(chalk.dim(` [intent-runtime] context load skipped: ${err.message}`));
2462
+ }
2463
+ }
2464
+ if (localActiveContext) {
2465
+ try {
2466
+ localGovernanceResult = (0, governance_1.evaluateGovernance)({
2467
+ projectRoot,
2468
+ task: localActiveContext.intentPack.intent.normalized,
2469
+ expectedFiles: localActiveContext.intentPack.approvedScope.files,
2470
+ expectedDependencies: localActiveContext.intentPack.expectedDependencies,
2471
+ diffFiles,
2472
+ contextCandidates: localActiveContext.contextPack.selectedFiles.map((f) => f.path),
2473
+ activeEngineeringContext: localActiveContext,
2474
+ });
2475
+ // Deterministic scope-guard intersection against intent-pack approvedScope
2476
+ // PLUS explicit forbiddenBoundaries. Drift intelligence already flags
2477
+ // narrative-level drift; this surfaces direct path violations as
2478
+ // first-class scope issues regardless of drift heuristics.
2479
+ const intent = localActiveContext.intentPack;
2480
+ const approvedFileSet = new Set(intent.approvedScope.files.map(core_1.normalizeRepoPath));
2481
+ const approvedModulePaths = intent.approvedScope.modules.map(core_1.normalizeRepoPath);
2482
+ const approvedServicePaths = intent.approvedScope.services.map(core_1.normalizeRepoPath);
2483
+ const matchesPrefix = (file, prefixes) => prefixes.some((p) => p && (file === p || file.startsWith(`${p}/`)));
2484
+ const changedNormalized = diffFiles
2485
+ .map((f) => (0, core_1.normalizeRepoPath)(f.path))
2486
+ .filter((p) => Boolean(p));
2487
+ const isAllowedBoundaryType = (value) => value === 'sensitive' || value === 'infra' || value === 'ci' ||
2488
+ value === 'dependency-manifest' || value === 'service' || value === 'module' ||
2489
+ value === 'generated-code' || value === 'unspecified';
2490
+ // First pass: explicit forbidden boundaries always surface (even if
2491
+ // they also happen to be inside an approved module).
2492
+ for (const boundary of intent.forbiddenBoundaries) {
2493
+ const boundaryPath = (0, core_1.normalizeRepoPath)(boundary.path);
2494
+ if (!boundaryPath)
2495
+ continue;
2496
+ for (const file of changedNormalized) {
2497
+ if (file === boundaryPath || file.startsWith(`${boundaryPath}/`)) {
2498
+ if (boundary.policy === 'allowed')
2499
+ continue;
2500
+ const alreadyFlagged = localScopeIssues.some((s) => s.file === file && s.boundaryType === boundary.type);
2501
+ if (alreadyFlagged)
2502
+ continue;
2503
+ const boundaryType = isAllowedBoundaryType(boundary.type) ? boundary.type : 'unspecified';
2504
+ localScopeIssues.push({
2505
+ file,
2506
+ message: `Forbidden boundary touched (${boundary.type}, policy=${boundary.policy}): ${boundary.reason}`,
2507
+ policy: boundary.policy === 'forbidden' ? 'forbidden' : 'review-required',
2508
+ boundaryType,
2509
+ });
2510
+ }
2511
+ }
2512
+ }
2513
+ // Second pass: out-of-scope files (not in approved file/module/service set).
2514
+ // Only run if any approvedScope dimension is non-empty — empty scope means
2515
+ // intent-pack is in observation mode and we should not synthesise FPs.
2516
+ // When a file falls outside scope, we additionally classify it against
2517
+ // well-known path patterns (generated-code, infra, CI, dependency-manifest)
2518
+ // so reviewers see WHY the boundary matters, not just THAT it was breached.
2519
+ const hasApprovedScope = approvedFileSet.size > 0 || approvedModulePaths.length > 0 || approvedServicePaths.length > 0;
2520
+ if (hasApprovedScope) {
2521
+ for (const file of changedNormalized) {
2522
+ if (approvedFileSet.has(file))
2523
+ continue;
2524
+ if (matchesPrefix(file, approvedModulePaths))
2525
+ continue;
2526
+ if (matchesPrefix(file, approvedServicePaths))
2527
+ continue;
2528
+ if (localScopeIssues.some((s) => s.file === file))
2529
+ continue;
2530
+ const classification = (0, path_boundary_classifier_1.classifyPathBoundary)(file);
2531
+ if (classification) {
2532
+ // generated-code is a stronger signal than plain out-of-scope:
2533
+ // generated files should not be hand-edited regardless of
2534
+ // approval status.
2535
+ if (classification.category === 'generated-code') {
2536
+ localScopeIssues.push({
2537
+ file,
2538
+ message: `Generated-code edit outside approved scope (${classification.reason}). Regenerate from source or update the intent-pack to declare this surface.`,
2539
+ policy: 'generated-code',
2540
+ boundaryType: 'generated-code',
2541
+ });
2542
+ continue;
2543
+ }
2544
+ const boundaryType = isAllowedBoundaryType(classification.category) ? classification.category : 'unspecified';
2545
+ localScopeIssues.push({
2546
+ file,
2547
+ message: `File modified outside the declared intent scope (${classification.category}: ${classification.reason}).`,
2548
+ policy: 'out-of-scope',
2549
+ boundaryType,
2550
+ });
2551
+ continue;
2552
+ }
2553
+ localScopeIssues.push({
2554
+ file,
2555
+ message: 'File modified outside the declared intent scope.',
2556
+ policy: 'out-of-scope',
2557
+ });
2558
+ }
2559
+ }
2560
+ else {
2561
+ // Observation mode (no approved scope): only surface generated-code
2562
+ // edits, because those are usually wrong regardless of intent.
2563
+ for (const file of changedNormalized) {
2564
+ if (localScopeIssues.some((s) => s.file === file))
2565
+ continue;
2566
+ const classification = (0, path_boundary_classifier_1.classifyPathBoundary)(file);
2567
+ if (classification?.category === 'generated-code') {
2568
+ localScopeIssues.push({
2569
+ file,
2570
+ message: `Generated-code edit detected (${classification.reason}). Regenerate from source.`,
2571
+ policy: 'generated-code',
2572
+ boundaryType: 'generated-code',
2573
+ });
2574
+ }
2575
+ }
2576
+ }
2577
+ // ─── Import-edge governance ──────────────────────────────────────
2578
+ // Deterministic import-edge classifier: even when every touched
2579
+ // path is in-scope, an `import` statement that crosses a
2580
+ // forbidden boundary surfaces as a scope issue. Closes the
2581
+ // semantic blind spot documented in
2582
+ // docs/validation/2026-05-17-deep-oss/.
2583
+ try {
2584
+ localImportEdgeResult = (0, import_edge_governance_1.evaluateImportEdgeGovernance)({
2585
+ diffFiles,
2586
+ projectRoot,
2587
+ intent: {
2588
+ approvedScope: {
2589
+ files: intent.approvedScope.files,
2590
+ modules: intent.approvedScope.modules,
2591
+ services: intent.approvedScope.services,
2592
+ },
2593
+ forbiddenBoundaries: intent.forbiddenBoundaries.map((b) => ({
2594
+ type: b.type,
2595
+ path: b.path,
2596
+ policy: b.policy,
2597
+ reason: b.reason,
2598
+ })),
2599
+ },
2600
+ });
2601
+ for (const finding of localImportEdgeResult.findings) {
2602
+ // Avoid double-flagging when the same source file already has
2603
+ // a path-touch issue for the same boundary; import-edge is
2604
+ // additive metadata in that case.
2605
+ const dupe = localScopeIssues.some((s) => s.file === finding.sourceFile
2606
+ && s.importEdge
2607
+ && s.importEdge.importTarget === finding.importTarget
2608
+ && s.importEdge.resolvedBoundary === finding.resolvedBoundary);
2609
+ if (dupe)
2610
+ continue;
2611
+ localScopeIssues.push({
2612
+ file: finding.sourceFile,
2613
+ message: `Import-edge crosses ${finding.boundaryType} boundary (policy=${finding.policy}): \`${finding.importTarget}\` resolves to \`${finding.resolvedTargetPath}\` inside \`${finding.resolvedBoundary}\`. ${finding.reason}`,
2614
+ policy: finding.policy,
2615
+ boundaryType: finding.boundaryType,
2616
+ importEdge: {
2617
+ sourceFile: finding.sourceFile,
2618
+ sourceLine: finding.sourceLine,
2619
+ importTarget: finding.importTarget,
2620
+ resolvedTargetPath: finding.resolvedTargetPath,
2621
+ resolvedBoundary: finding.resolvedBoundary,
2622
+ edgeKind: finding.edgeKind,
2623
+ language: finding.language,
2624
+ deterministic: true,
2625
+ replayStable: true,
2626
+ },
2627
+ });
2628
+ }
2629
+ }
2630
+ catch (importErr) {
2631
+ if (!options.json && (process.env.DEBUG || process.env.VERBOSE)) {
2632
+ console.log(chalk.dim(` [intent-runtime] import-edge governance skipped: ${importErr.message}`));
2633
+ }
2634
+ }
2635
+ }
2636
+ catch (err) {
2637
+ if (!options.json && (process.env.DEBUG || process.env.VERBOSE)) {
2638
+ console.log(chalk.dim(` [intent-runtime] governance evaluation skipped: ${err.message}`));
2639
+ }
2640
+ }
2641
+ }
2642
+ const blockingScopeCount = localScopeIssues.filter((s) => s.policy === 'forbidden' || s.policy === 'out-of-scope' || s.policy === 'generated-code').length;
2643
+ const advisoryScopeCount = localScopeIssues.filter((s) => s.policy === 'review-required').length;
2644
+ const intentRuntimeActive = Boolean(localGovernanceResult);
2645
+ const localScopeGuardPassed = blockingScopeCount === 0;
2646
+ // `--require-intent-runtime` (or NEURCODE_REQUIRE_INTENT_RUNTIME=1) makes
2647
+ // silent downgrade into a hard failure. Without this flag the runtime
2648
+ // gracefully degrades to structural-only when no intent contract exists;
2649
+ // with it, enterprise CI gates can assert intent governance was applied.
2650
+ const requireIntentRuntimeFlag = options.requireIntentRuntime === true || isEnabledFlag(process.env.NEURCODE_REQUIRE_INTENT_RUNTIME);
2651
+ const intentRuntimeRequirementFailed = requireIntentRuntimeFlag && !intentRuntimeActive;
2652
+ const localVerdict = blockingViolations.length > 0 || blockingScopeCount > 0 || intentRuntimeRequirementFailed ? 'FAIL' : 'PASS';
2653
+ const localGrade = localVerdict === 'FAIL' ? 'F' : 'B';
2654
+ const localScore = localVerdict === 'FAIL' ? 0 : 70;
2655
+ const scopeViolationRows = localScopeIssues
2656
+ .filter((s) => s.policy === 'forbidden' || s.policy === 'out-of-scope' || s.policy === 'generated-code')
2657
+ .map((s) => ({
2658
+ file: s.file,
2659
+ rule: 'scope_guard',
2660
+ severity: 'block',
2661
+ message: s.message,
2662
+ }));
2663
+ const scopeWarningRows = localScopeIssues
2664
+ .filter((s) => s.policy === 'review-required')
2665
+ .map((s) => ({
2666
+ file: s.file,
2667
+ rule: 'scope_guard',
2668
+ severity: 'warn',
2669
+ message: s.message,
2670
+ }));
2671
+ // Surface the intent-runtime requirement failure as a first-class
2672
+ // governance row so CI logs, dashboards, and PR comments all see the
2673
+ // same explanation. The row sits next to scope_guard rows so it shares
2674
+ // their treatment (block, blocking-count, exit code).
2675
+ const intentRuntimeRequirementRows = intentRuntimeRequirementFailed
2676
+ ? [{
2677
+ file: '.neurcode/intent-pack.json',
2678
+ rule: 'intent_runtime_required',
2679
+ severity: 'block',
2680
+ message: 'Intent-governed runtime required (--require-intent-runtime / NEURCODE_REQUIRE_INTENT_RUNTIME=1) but no `.neurcode/intent-pack.json` was found or it could not be synthesised. Either author an intent pack (`neurcode start`) or drop the requirement to allow structural-only verification.',
2681
+ }]
2682
+ : [];
2378
2683
  const localPayload = {
2379
2684
  grade: localGrade,
2380
2685
  score: localScore,
2381
2686
  verdict: localVerdict,
2382
- violations: localStructural.violations.map((v) => ({
2383
- file: v.filePath,
2384
- rule: v.ruleId,
2385
- severity: v.severity === 'BLOCKING' ? 'block' : 'warn',
2386
- message: `${v.ruleName}: ${v.evidence.slice(0, 120)}`,
2387
- })),
2687
+ violations: [
2688
+ ...localStructural.violations.map((v) => ({
2689
+ file: v.filePath,
2690
+ rule: v.ruleId,
2691
+ severity: v.severity === 'BLOCKING' ? 'block' : 'warn',
2692
+ message: `${v.ruleName}: ${v.evidence.slice(0, 120)}`,
2693
+ })),
2694
+ ...scopeViolationRows,
2695
+ ...scopeWarningRows,
2696
+ ...intentRuntimeRequirementRows,
2697
+ ],
2388
2698
  adherenceScore: localScore,
2389
- bloatCount: 0,
2390
- bloatFiles: [],
2699
+ bloatCount: blockingScopeCount,
2700
+ bloatFiles: scopeViolationRows.map((r) => r.file),
2391
2701
  plannedFilesModified: 0,
2392
2702
  totalPlannedFiles: 0,
2393
- message: `Local-only structural verification: ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking.`,
2394
- scopeGuardPassed: true,
2395
- mode: 'local_only_structural',
2703
+ message: intentRuntimeRequirementFailed
2704
+ ? 'Intent-runtime requirement failed: no `.neurcode/intent-pack.json` available to activate scope + forbidden-boundary enforcement.'
2705
+ : (intentRuntimeActive
2706
+ ? `Local intent-runtime verification: ${localStructural.violations.length} structural finding(s), ${blockingViolations.length} blocking; ${blockingScopeCount} scope violation(s), ${advisoryScopeCount} advisory boundary issue(s).`
2707
+ : `Local-only structural verification: ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking.`),
2708
+ scopeGuardPassed: localScopeGuardPassed,
2709
+ scopeIssues: localScopeIssues.map((s) => ({
2710
+ file: s.file,
2711
+ message: s.message,
2712
+ policy: s.policy,
2713
+ boundaryType: s.boundaryType,
2714
+ ...(s.importEdge ? { importEdge: s.importEdge } : {}),
2715
+ })),
2716
+ mode: intentRuntimeActive ? 'local_intent_runtime' : 'local_only_structural',
2396
2717
  policyOnly: true,
2397
- replayChecksum: localReplayChecksum,
2398
- replayMode: 'local-structural',
2718
+ // NOTE: this is the structural-only checksum. When the canonical
2719
+ // envelope is attached below, `governanceVerification.replayChecksum`
2720
+ // becomes the authoritative hash over the merged finding set
2721
+ // (structural + drift + scope). The top-level `replayChecksum` is
2722
+ // rewritten post-attach so enterprise CI sees a single canonical
2723
+ // hash for the activated runtime.
2724
+ replayChecksum: (0, canonical_invariants_1.computeCanonicalFindingChecksum)(localStructuralFindings),
2725
+ replayMode: intentRuntimeActive ? 'local-intent-runtime' : 'local-structural',
2399
2726
  structuralViolations: localStructural.violations,
2400
2727
  structuralBlockingCount: blockingViolations.length,
2401
2728
  structuralRulesApplied: localStructural.rulesApplied,
2402
2729
  changeContract: changeContractSummary,
2730
+ // driftIntelligence drives intentGovernance summary + drift findings
2731
+ // inside attachCanonicalGovernance.
2732
+ driftIntelligence: localGovernanceResult?.driftIntelligence ?? null,
2733
+ engineeringContext: localGovernanceResult?.engineeringContext ?? null,
2734
+ intentRuntime: localActiveContext
2735
+ ? {
2736
+ active: true,
2737
+ synthesized: Boolean(localActiveContext.synthesized),
2738
+ intentPackId: localActiveContext.intentPack.intentPackId,
2739
+ contextPackId: localActiveContext.contextPack.contextPackId,
2740
+ repositoryGraphId: localActiveContext.repositoryGraph.graphId,
2741
+ warnings: localActiveContext.warnings,
2742
+ }
2743
+ : { active: false, synthesized: false, intentPackId: null, contextPackId: null, repositoryGraphId: null, warnings: [] },
2744
+ // Machine-readable capability declaration for enterprise CI. Every
2745
+ // field is "what actually executed", not "what we wished happened".
2746
+ // CI gates that need a specific guarantee (e.g. intent-runtime active,
2747
+ // generated-code governance active) can assert against this envelope
2748
+ // rather than inferring from absence of fields. See
2749
+ // docs/validation/2026-05-16-activated/activation-report-2026-05-16.md
2750
+ // §6 for the rationale.
2751
+ runtimeCapabilities: {
2752
+ schemaVersion: 'neurcode.runtime-capabilities.v1',
2753
+ executionPath: 'local-only',
2754
+ intentRuntime: intentRuntimeActive
2755
+ ? (localActiveContext?.synthesized ? 'active-synthesized' : 'active-authored')
2756
+ : 'inactive',
2757
+ intentContractSource: localActiveContext
2758
+ ? (localActiveContext.synthesized ? 'intent-pack-only' : 'full-bundle')
2759
+ : 'none',
2760
+ // Reflect whether the caller required intent runtime to be active.
2761
+ // Mirrors how `requireRuntimeGuard` is surfaced; lets dashboards
2762
+ // distinguish "intent runtime inactive by choice" from
2763
+ // "intent runtime inactive against caller policy".
2764
+ intentRuntimeRequired: requireIntentRuntimeFlag,
2765
+ intentRuntimeRequirementSatisfied: !intentRuntimeRequirementFailed,
2766
+ driftIntelligence: localGovernanceResult?.driftIntelligence ? 'active' : 'inactive',
2767
+ scopeGuard: intentRuntimeActive ? 'enforced' : 'unenforced',
2768
+ forbiddenBoundaryEnforcement: intentRuntimeActive ? 'enforced' : 'unenforced',
2769
+ generatedCodeGovernance: 'pattern-deterministic',
2770
+ // Import-edge governance is enforced whenever the intent runtime
2771
+ // is active. Pattern-deterministic (regex over diff additions +
2772
+ // path classifier), no AST, no probability.
2773
+ importEdgeGovernance: intentRuntimeActive ? 'pattern-deterministic' : 'inactive',
2774
+ structuralRules: 'active',
2775
+ replayDeterminism: 'enforced',
2776
+ apiContractStatus: 'offline',
2777
+ // Counts of categories observed in THIS run (not capacity).
2778
+ observedScopeCategories: Array.from(new Set(localScopeIssues.map((s) => s.policy))).sort(),
2779
+ observedBoundaryTypes: Array.from(new Set(localScopeIssues
2780
+ .map((s) => s.boundaryType)
2781
+ .filter((b) => Boolean(b)))).sort(),
2782
+ // Import-edge observability — counts only, plus a sorted list of
2783
+ // observed boundary types from the edge pass. Helpful for CI gates
2784
+ // that want to assert "this run had ≥0 edges analysed".
2785
+ importEdgesAnalyzed: localImportEdgeResult?.edgeCount ?? 0,
2786
+ importEdgeBlockingFindings: localImportEdgeResult?.blockingFindingCount ?? 0,
2787
+ importEdgeAdvisoryFindings: localImportEdgeResult?.advisoryFindingCount ?? 0,
2788
+ observedImportEdgeBoundaryTypes: localImportEdgeResult?.observedBoundaryTypes ?? [],
2789
+ },
2403
2790
  };
2404
- captureEvidencePayload((0, canonical_pipeline_1.attachCanonicalGovernance)(localPayload));
2791
+ // Run the canonical pipeline once so we can extract the merged-finding
2792
+ // replayChecksum (structural + drift + scope) and back-write it to the
2793
+ // top-level payload + custody envelope. This keeps a single authoritative
2794
+ // hash visible at every replay surface when the intent runtime is active.
2795
+ const enrichedLocalPayload = (0, canonical_pipeline_1.attachCanonicalGovernance)(localPayload);
2796
+ const envelopeReplayChecksum = (() => {
2797
+ const env = enrichedLocalPayload.governanceVerification;
2798
+ return env && typeof env.replayChecksum === 'string' ? env.replayChecksum : localPayload.replayChecksum;
2799
+ })();
2800
+ enrichedLocalPayload.replayChecksum = envelopeReplayChecksum;
2801
+ localPayload.replayChecksum = envelopeReplayChecksum;
2802
+ captureEvidencePayload(enrichedLocalPayload);
2405
2803
  const localReplayCustody = (0, replay_custody_1.captureVerifyReplayCustody)({
2406
2804
  projectRoot,
2407
2805
  diffContext: `${options.base || 'HEAD'} vs working tree`,
2408
2806
  filesAnalyzed: diffFiles.length,
2409
2807
  planId: null,
2410
- verificationSource: 'local_only_structural',
2808
+ verificationSource: intentRuntimeActive ? 'local_intent_runtime' : 'local_only_structural',
2411
2809
  policyLockFingerprint: null,
2412
2810
  compiledPolicyFingerprint: null,
2413
2811
  ruleIds: localStructural.rulesApplied,
2414
- blockingCount: blockingViolations.length,
2415
- advisoryCount: advisoryViolations.length,
2812
+ blockingCount: blockingViolations.length + blockingScopeCount,
2813
+ advisoryCount: advisoryViolations.length + advisoryScopeCount,
2416
2814
  suppressedCount: localStructural.suppressedCount,
2417
2815
  structuralBlockingCount: blockingViolations.length,
2418
2816
  structuralAdvisoryCount: advisoryViolations.length,
@@ -2422,10 +2820,12 @@ async function verifyCommand(options) {
2422
2820
  ? Math.round((localStructural.violations.filter((v) => v.determinism === 'deterministic-structural').length / localStructural.violations.length) * 100)
2423
2821
  : 100,
2424
2822
  verdict: localVerdict,
2425
- governanceDecision: 'local deterministic structural verification',
2823
+ governanceDecision: intentRuntimeActive
2824
+ ? `local intent-runtime verification${localActiveContext?.synthesized ? ' (synthesised context)' : ''}`
2825
+ : 'local deterministic structural verification',
2426
2826
  actor: custodyActor,
2427
2827
  source: custodySource,
2428
- replayChecksum: localReplayChecksum,
2828
+ replayChecksum: envelopeReplayChecksum,
2429
2829
  });
2430
2830
  applyCapturedReplayCustody(lastCanonicalOutput, localReplayCustody);
2431
2831
  if (options.json) {
@@ -2435,8 +2835,10 @@ async function verifyCommand(options) {
2435
2835
  });
2436
2836
  }
2437
2837
  else {
2438
- if (localStructural.violations.length === 0) {
2439
- console.log(chalk.green('\n✅ No structural violations found (local-only mode).'));
2838
+ if (localStructural.violations.length === 0 && localScopeIssues.length === 0) {
2839
+ console.log(chalk.green(intentRuntimeActive
2840
+ ? '\n✅ No structural or scope violations found (intent-runtime active, local-only).'
2841
+ : '\n✅ No structural violations found (local-only mode).'));
2440
2842
  }
2441
2843
  else {
2442
2844
  localStructural.violations.forEach((v) => {
@@ -2445,14 +2847,42 @@ async function verifyCommand(options) {
2445
2847
  console.log(chalk.dim(` ${v.ruleName}`));
2446
2848
  console.log(chalk.dim(` ${v.evidence.slice(0, 100)}`));
2447
2849
  });
2850
+ for (const issue of localScopeIssues) {
2851
+ const prefix = issue.policy === 'forbidden' || issue.policy === 'out-of-scope'
2852
+ ? chalk.red(' ⛔ SCOPE ')
2853
+ : chalk.yellow(' ⚠ SCOPE ');
2854
+ console.log(`${prefix} ${issue.file}`);
2855
+ console.log(chalk.dim(` ${issue.message}`));
2856
+ }
2448
2857
  }
2449
- console.log(chalk.dim(`\n[Local-only] ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking. ` +
2450
- `Structural analysis ran on this checkout only (no verify API).\n`));
2451
- console.log(chalk.dim(' Replay: same commit + same flags → same structural findings.\n' +
2452
- ' Full plan/adherence + remote verify: drop --local-only when policy allows network/API.\n'));
2453
- }
2454
- recordVerifyEvent(localVerdict, `local_only;structural=${localStructural.violations.length}`, diffFiles.map((f) => f.path));
2455
- exitWithEvidence(blockingViolations.length > 0 ? 2 : 0);
2858
+ const modeLabel = intentRuntimeActive
2859
+ ? (localActiveContext?.synthesized ? 'Local intent-runtime (synthesised context)' : 'Local intent-runtime')
2860
+ : 'Local-only structural';
2861
+ console.log(chalk.dim(`\n[${modeLabel}] ${localStructural.violations.length} structural finding(s), ` +
2862
+ `${blockingViolations.length} blocking; ${localScopeIssues.length} scope issue(s), ${blockingScopeCount} blocking.\n`));
2863
+ // Governance posture banner: surface gate + rollout trust prominently
2864
+ // when the intent runtime is active so the most-glanced terminal line
2865
+ // reflects the canonical governance lifecycle, not just verify counts.
2866
+ if (intentRuntimeActive && localGovernanceResult?.driftIntelligence) {
2867
+ const drift = localGovernanceResult.driftIntelligence;
2868
+ const gate = drift.riskSynthesis?.governanceGate || drift.governancePosture?.governanceGate;
2869
+ const rolloutTrust = drift.riskSynthesis?.rolloutTrust || drift.governancePosture?.rolloutTrust;
2870
+ if (gate || rolloutTrust) {
2871
+ const gateLabel = gate ? `gate=${chalk.bold(gate)}` : 'gate=advisory';
2872
+ const trustLabel = rolloutTrust ? `rollout-trust=${chalk.bold(rolloutTrust)}` : 'rollout-trust=rollout-safe';
2873
+ console.log(chalk.dim(` Governance posture: ${gateLabel} · ${trustLabel}\n`));
2874
+ }
2875
+ }
2876
+ console.log(chalk.dim(` Replay: same commit + same flags + same intent-pack → same canonical checksum.\n` +
2877
+ ` Replay checksum: ${envelopeReplayChecksum.slice(0, 16)}…\n` +
2878
+ (intentRuntimeActive
2879
+ ? ' Intent governance: ACTIVE (offline). Add full intent-runtime artefacts for richer semantic narratives.\n'
2880
+ : ' Intent governance: INACTIVE. Add `.neurcode/intent-pack.json` to activate scope + forbidden-boundary enforcement locally.\n')));
2881
+ }
2882
+ recordVerifyEvent(localVerdict, intentRuntimeActive
2883
+ ? `local_intent_runtime;structural=${localStructural.violations.length};scope=${localScopeIssues.length}`
2884
+ : `local_only;structural=${localStructural.violations.length}`, diffFiles.map((f) => f.path));
2885
+ exitWithEvidence(localVerdict === 'FAIL' ? 2 : 0);
2456
2886
  }
2457
2887
  const summary = (0, diff_parser_1.getDiffSummary)(diffFiles);
2458
2888
  if (diffFiles.length === 0) {