@neurcode-ai/cli 0.9.63 → 0.9.65

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 (308) hide show
  1. package/LICENSE +201 -0
  2. package/dist/commands/brain.d.ts.map +1 -1
  3. package/dist/commands/brain.js +273 -0
  4. package/dist/commands/brain.js.map +1 -1
  5. package/dist/commands/control-plane.js +7 -7
  6. package/dist/commands/control-plane.js.map +1 -1
  7. package/dist/commands/fix.d.ts.map +1 -1
  8. package/dist/commands/fix.js +108 -1
  9. package/dist/commands/fix.js.map +1 -1
  10. package/dist/commands/patch-apply.d.ts +2 -0
  11. package/dist/commands/patch-apply.d.ts.map +1 -1
  12. package/dist/commands/patch-apply.js +331 -19
  13. package/dist/commands/patch-apply.js.map +1 -1
  14. package/dist/commands/pilot-report.d.ts +9 -0
  15. package/dist/commands/pilot-report.d.ts.map +1 -0
  16. package/dist/commands/pilot-report.js +176 -0
  17. package/dist/commands/pilot-report.js.map +1 -0
  18. package/dist/commands/remediate-governance.d.ts +54 -0
  19. package/dist/commands/remediate-governance.d.ts.map +1 -0
  20. package/dist/commands/remediate-governance.js +375 -0
  21. package/dist/commands/remediate-governance.js.map +1 -0
  22. package/dist/commands/remediate.d.ts.map +1 -1
  23. package/dist/commands/remediate.js.map +1 -1
  24. package/dist/commands/replay.d.ts.map +1 -1
  25. package/dist/commands/replay.js +35 -5
  26. package/dist/commands/replay.js.map +1 -1
  27. package/dist/commands/verify.d.ts.map +1 -1
  28. package/dist/commands/verify.js +336 -25
  29. package/dist/commands/verify.js.map +1 -1
  30. package/dist/commands/workspace.js +7 -7
  31. package/dist/commands/workspace.js.map +1 -1
  32. package/dist/daemon/server.d.ts +2 -2
  33. package/dist/daemon/server.d.ts.map +1 -1
  34. package/dist/daemon/server.js +2113 -32
  35. package/dist/daemon/server.js.map +1 -1
  36. package/dist/explainability/DeterminismClassifier.d.ts +34 -0
  37. package/dist/explainability/DeterminismClassifier.d.ts.map +1 -0
  38. package/dist/explainability/DeterminismClassifier.js +104 -0
  39. package/dist/explainability/DeterminismClassifier.js.map +1 -0
  40. package/dist/explainability/ViolationFormatter.d.ts +32 -0
  41. package/dist/explainability/ViolationFormatter.d.ts.map +1 -0
  42. package/dist/explainability/ViolationFormatter.js +252 -0
  43. package/dist/explainability/ViolationFormatter.js.map +1 -0
  44. package/dist/explainability/index.d.ts +15 -0
  45. package/dist/explainability/index.d.ts.map +1 -0
  46. package/dist/explainability/index.js +94 -0
  47. package/dist/explainability/index.js.map +1 -0
  48. package/dist/explainability/types.d.ts +37 -0
  49. package/dist/explainability/types.d.ts.map +1 -0
  50. package/dist/explainability/types.js +3 -0
  51. package/dist/explainability/types.js.map +1 -0
  52. package/dist/governance/canonical-pipeline.d.ts +38 -0
  53. package/dist/governance/canonical-pipeline.d.ts.map +1 -0
  54. package/dist/governance/canonical-pipeline.js +448 -0
  55. package/dist/governance/canonical-pipeline.js.map +1 -0
  56. package/dist/governance/structural-on-diff.d.ts +13 -0
  57. package/dist/governance/structural-on-diff.d.ts.map +1 -0
  58. package/dist/governance/structural-on-diff.js +35 -0
  59. package/dist/governance/structural-on-diff.js.map +1 -0
  60. package/dist/governance/structural-policy-merge.d.ts +14 -0
  61. package/dist/governance/structural-policy-merge.d.ts.map +1 -0
  62. package/dist/governance/structural-policy-merge.js +25 -0
  63. package/dist/governance/structural-policy-merge.js.map +1 -0
  64. package/dist/index.js +86 -4
  65. package/dist/index.js.map +1 -1
  66. package/dist/integrations/review-compression/index.d.ts +50 -0
  67. package/dist/integrations/review-compression/index.d.ts.map +1 -0
  68. package/dist/integrations/review-compression/index.js +158 -0
  69. package/dist/integrations/review-compression/index.js.map +1 -0
  70. package/dist/intent-engine/domain-taxonomy.d.ts +42 -0
  71. package/dist/intent-engine/domain-taxonomy.d.ts.map +1 -0
  72. package/dist/intent-engine/domain-taxonomy.js +534 -0
  73. package/dist/intent-engine/domain-taxonomy.js.map +1 -0
  74. package/dist/intent-engine/index.d.ts +1 -0
  75. package/dist/intent-engine/index.d.ts.map +1 -1
  76. package/dist/intent-engine/index.js +6 -1
  77. package/dist/intent-engine/index.js.map +1 -1
  78. package/dist/intent-engine/matcher.d.ts.map +1 -1
  79. package/dist/intent-engine/matcher.js +2 -0
  80. package/dist/intent-engine/matcher.js.map +1 -1
  81. package/dist/intent-engine/parser.d.ts.map +1 -1
  82. package/dist/intent-engine/parser.js +47 -0
  83. package/dist/intent-engine/parser.js.map +1 -1
  84. package/dist/intent-engine/semantic-expander.d.ts +104 -0
  85. package/dist/intent-engine/semantic-expander.d.ts.map +1 -0
  86. package/dist/intent-engine/semantic-expander.js +480 -0
  87. package/dist/intent-engine/semantic-expander.js.map +1 -0
  88. package/dist/patch-engine/diff.d.ts +1 -1
  89. package/dist/patch-engine/diff.js +1 -1
  90. package/dist/patch-engine/generator.d.ts +9 -0
  91. package/dist/patch-engine/generator.d.ts.map +1 -1
  92. package/dist/patch-engine/generator.js +375 -17
  93. package/dist/patch-engine/generator.js.map +1 -1
  94. package/dist/patch-engine/index.d.ts +25 -25
  95. package/dist/patch-engine/index.d.ts.map +1 -1
  96. package/dist/patch-engine/index.js +134 -87
  97. package/dist/patch-engine/index.js.map +1 -1
  98. package/dist/patch-engine/patterns.d.ts +1 -1
  99. package/dist/patch-engine/patterns.d.ts.map +1 -1
  100. package/dist/patch-engine/patterns.js +282 -41
  101. package/dist/patch-engine/patterns.js.map +1 -1
  102. package/dist/patch-engine/rollback.d.ts +31 -0
  103. package/dist/patch-engine/rollback.d.ts.map +1 -0
  104. package/dist/patch-engine/rollback.js +275 -0
  105. package/dist/patch-engine/rollback.js.map +1 -0
  106. package/dist/patch-engine/safety.d.ts +28 -0
  107. package/dist/patch-engine/safety.d.ts.map +1 -0
  108. package/dist/patch-engine/safety.js +122 -0
  109. package/dist/patch-engine/safety.js.map +1 -0
  110. package/dist/patch-engine/transaction.d.ts +52 -0
  111. package/dist/patch-engine/transaction.d.ts.map +1 -0
  112. package/dist/patch-engine/transaction.js +93 -0
  113. package/dist/patch-engine/transaction.js.map +1 -0
  114. package/dist/semantic/index.d.ts +14 -0
  115. package/dist/semantic/index.d.ts.map +1 -0
  116. package/dist/semantic/index.js +30 -0
  117. package/dist/semantic/index.js.map +1 -0
  118. package/dist/semantic/tfidf-engine.d.ts +81 -0
  119. package/dist/semantic/tfidf-engine.d.ts.map +1 -0
  120. package/dist/semantic/tfidf-engine.js +278 -0
  121. package/dist/semantic/tfidf-engine.js.map +1 -0
  122. package/dist/semantic/vector-store.d.ts +108 -0
  123. package/dist/semantic/vector-store.d.ts.map +1 -0
  124. package/dist/semantic/vector-store.js +321 -0
  125. package/dist/semantic/vector-store.js.map +1 -0
  126. package/dist/structural-rules/context-severity.d.ts +46 -0
  127. package/dist/structural-rules/context-severity.d.ts.map +1 -0
  128. package/dist/structural-rules/context-severity.js +115 -0
  129. package/dist/structural-rules/context-severity.js.map +1 -0
  130. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts +11 -0
  131. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.d.ts.map +1 -0
  132. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js +212 -0
  133. package/dist/structural-rules/distributed/DS001-saga-rollback-absence.js.map +1 -0
  134. package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts +11 -0
  135. package/dist/structural-rules/distributed/DS002-missing-correlation-id.d.ts.map +1 -0
  136. package/dist/structural-rules/distributed/DS002-missing-correlation-id.js +213 -0
  137. package/dist/structural-rules/distributed/DS002-missing-correlation-id.js.map +1 -0
  138. package/dist/structural-rules/distributed/index.d.ts +3 -0
  139. package/dist/structural-rules/distributed/index.d.ts.map +1 -0
  140. package/dist/structural-rules/distributed/index.js +8 -0
  141. package/dist/structural-rules/distributed/index.js.map +1 -0
  142. package/dist/structural-rules/engine.d.ts +25 -0
  143. package/dist/structural-rules/engine.d.ts.map +1 -0
  144. package/dist/structural-rules/engine.js +90 -0
  145. package/dist/structural-rules/engine.js.map +1 -0
  146. package/dist/structural-rules/index.d.ts +41 -0
  147. package/dist/structural-rules/index.d.ts.map +1 -0
  148. package/dist/structural-rules/index.js +141 -0
  149. package/dist/structural-rules/index.js.map +1 -0
  150. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts +11 -0
  151. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.d.ts.map +1 -0
  152. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js +66 -0
  153. package/dist/structural-rules/python/PY001-asyncio-task-without-cancel.js.map +1 -0
  154. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts +11 -0
  155. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.d.ts.map +1 -0
  156. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js +135 -0
  157. package/dist/structural-rules/python/PY002-unbounded-dict-singleton.js.map +1 -0
  158. package/dist/structural-rules/python/PY003-broad-except-clause.d.ts +11 -0
  159. package/dist/structural-rules/python/PY003-broad-except-clause.d.ts.map +1 -0
  160. package/dist/structural-rules/python/PY003-broad-except-clause.js +86 -0
  161. package/dist/structural-rules/python/PY003-broad-except-clause.js.map +1 -0
  162. package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts +11 -0
  163. package/dist/structural-rules/python/PY004-swallowed-async-exception.d.ts.map +1 -0
  164. package/dist/structural-rules/python/PY004-swallowed-async-exception.js +167 -0
  165. package/dist/structural-rules/python/PY004-swallowed-async-exception.js.map +1 -0
  166. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts +11 -0
  167. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.d.ts.map +1 -0
  168. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js +154 -0
  169. package/dist/structural-rules/python/PY005-fastapi-without-pydantic.js.map +1 -0
  170. package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts +11 -0
  171. package/dist/structural-rules/python/PY006-blocking-io-in-async.d.ts.map +1 -0
  172. package/dist/structural-rules/python/PY006-blocking-io-in-async.js +130 -0
  173. package/dist/structural-rules/python/PY006-blocking-io-in-async.js.map +1 -0
  174. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts +11 -0
  175. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.d.ts.map +1 -0
  176. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js +93 -0
  177. package/dist/structural-rules/python/PY007-sqlalchemy-session-leak.js.map +1 -0
  178. package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts +11 -0
  179. package/dist/structural-rules/python/PY008-celery-task-without-retry.d.ts.map +1 -0
  180. package/dist/structural-rules/python/PY008-celery-task-without-retry.js +154 -0
  181. package/dist/structural-rules/python/PY008-celery-task-without-retry.js.map +1 -0
  182. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts +11 -0
  183. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.d.ts.map +1 -0
  184. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js +133 -0
  185. package/dist/structural-rules/python/PY009-unsafe-pickle-deserialization.js.map +1 -0
  186. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts +11 -0
  187. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.d.ts.map +1 -0
  188. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js +80 -0
  189. package/dist/structural-rules/python/PY010-leaked-aiohttp-session.js.map +1 -0
  190. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts +11 -0
  191. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.d.ts.map +1 -0
  192. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js +145 -0
  193. package/dist/structural-rules/rules/SR001-swallowed-async-rejection.js.map +1 -0
  194. package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts +11 -0
  195. package/dist/structural-rules/rules/SR002-unbounded-collection.d.ts.map +1 -0
  196. package/dist/structural-rules/rules/SR002-unbounded-collection.js +196 -0
  197. package/dist/structural-rules/rules/SR002-unbounded-collection.js.map +1 -0
  198. package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts +11 -0
  199. package/dist/structural-rules/rules/SR003-timer-without-cleanup.d.ts.map +1 -0
  200. package/dist/structural-rules/rules/SR003-timer-without-cleanup.js +148 -0
  201. package/dist/structural-rules/rules/SR003-timer-without-cleanup.js.map +1 -0
  202. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts +11 -0
  203. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.d.ts.map +1 -0
  204. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js +162 -0
  205. package/dist/structural-rules/rules/SR004-request-boundary-no-validation.js.map +1 -0
  206. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts +11 -0
  207. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.d.ts.map +1 -0
  208. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js +150 -0
  209. package/dist/structural-rules/rules/SR005-halfopen-probe-gate.js.map +1 -0
  210. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts +11 -0
  211. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.d.ts.map +1 -0
  212. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js +161 -0
  213. package/dist/structural-rules/rules/SR006-fanout-error-sanitization.js.map +1 -0
  214. package/dist/structural-rules/rules/SR007-cross-request-error.d.ts +11 -0
  215. package/dist/structural-rules/rules/SR007-cross-request-error.d.ts.map +1 -0
  216. package/dist/structural-rules/rules/SR007-cross-request-error.js +175 -0
  217. package/dist/structural-rules/rules/SR007-cross-request-error.js.map +1 -0
  218. package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts +11 -0
  219. package/dist/structural-rules/rules/SR008-background-task-orphan.d.ts.map +1 -0
  220. package/dist/structural-rules/rules/SR008-background-task-orphan.js +176 -0
  221. package/dist/structural-rules/rules/SR008-background-task-orphan.js.map +1 -0
  222. package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts +11 -0
  223. package/dist/structural-rules/rules/SR009-missing-retry-backoff.d.ts.map +1 -0
  224. package/dist/structural-rules/rules/SR009-missing-retry-backoff.js +168 -0
  225. package/dist/structural-rules/rules/SR009-missing-retry-backoff.js.map +1 -0
  226. package/dist/structural-rules/rules/SR010-retry-storm.d.ts +11 -0
  227. package/dist/structural-rules/rules/SR010-retry-storm.d.ts.map +1 -0
  228. package/dist/structural-rules/rules/SR010-retry-storm.js +181 -0
  229. package/dist/structural-rules/rules/SR010-retry-storm.js.map +1 -0
  230. package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts +11 -0
  231. package/dist/structural-rules/rules/SR011-event-listener-leak.d.ts.map +1 -0
  232. package/dist/structural-rules/rules/SR011-event-listener-leak.js +208 -0
  233. package/dist/structural-rules/rules/SR011-event-listener-leak.js.map +1 -0
  234. package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts +11 -0
  235. package/dist/structural-rules/rules/SR012-promise-race-leak.d.ts.map +1 -0
  236. package/dist/structural-rules/rules/SR012-promise-race-leak.js +191 -0
  237. package/dist/structural-rules/rules/SR012-promise-race-leak.js.map +1 -0
  238. package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts +11 -0
  239. package/dist/structural-rules/rules/SR013-missing-idempotency-key.d.ts.map +1 -0
  240. package/dist/structural-rules/rules/SR013-missing-idempotency-key.js +219 -0
  241. package/dist/structural-rules/rules/SR013-missing-idempotency-key.js.map +1 -0
  242. package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts +11 -0
  243. package/dist/structural-rules/rules/SR014-mutable-closure-async.d.ts.map +1 -0
  244. package/dist/structural-rules/rules/SR014-mutable-closure-async.js +208 -0
  245. package/dist/structural-rules/rules/SR014-mutable-closure-async.js.map +1 -0
  246. package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts +11 -0
  247. package/dist/structural-rules/rules/SR015-dangling-abort-controller.d.ts.map +1 -0
  248. package/dist/structural-rules/rules/SR015-dangling-abort-controller.js +190 -0
  249. package/dist/structural-rules/rules/SR015-dangling-abort-controller.js.map +1 -0
  250. package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts +11 -0
  251. package/dist/structural-rules/rules/SR016-unsafe-json-parse.d.ts.map +1 -0
  252. package/dist/structural-rules/rules/SR016-unsafe-json-parse.js +187 -0
  253. package/dist/structural-rules/rules/SR016-unsafe-json-parse.js.map +1 -0
  254. package/dist/structural-rules/suppressions.d.ts +43 -0
  255. package/dist/structural-rules/suppressions.d.ts.map +1 -0
  256. package/dist/structural-rules/suppressions.js +115 -0
  257. package/dist/structural-rules/suppressions.js.map +1 -0
  258. package/dist/structural-rules/types.d.ts +43 -0
  259. package/dist/structural-rules/types.d.ts.map +1 -0
  260. package/dist/structural-rules/types.js +3 -0
  261. package/dist/structural-rules/types.js.map +1 -0
  262. package/dist/utils/advisory-signals.d.ts +5 -0
  263. package/dist/utils/advisory-signals.d.ts.map +1 -1
  264. package/dist/utils/advisory-signals.js +50 -12
  265. package/dist/utils/advisory-signals.js.map +1 -1
  266. package/dist/utils/ai-debt-budget.d.ts.map +1 -1
  267. package/dist/utils/ai-debt-budget.js +5 -2
  268. package/dist/utils/ai-debt-budget.js.map +1 -1
  269. package/dist/utils/brain-cache.d.ts +100 -0
  270. package/dist/utils/brain-cache.d.ts.map +1 -0
  271. package/dist/utils/brain-cache.js +346 -0
  272. package/dist/utils/brain-cache.js.map +1 -0
  273. package/dist/utils/cli-json.d.ts.map +1 -1
  274. package/dist/utils/cli-json.js +80 -12
  275. package/dist/utils/cli-json.js.map +1 -1
  276. package/dist/utils/execution-bus.d.ts +10 -0
  277. package/dist/utils/execution-bus.d.ts.map +1 -1
  278. package/dist/utils/execution-bus.js +16 -0
  279. package/dist/utils/execution-bus.js.map +1 -1
  280. package/dist/utils/governance-provenance.d.ts +95 -0
  281. package/dist/utils/governance-provenance.d.ts.map +1 -0
  282. package/dist/utils/governance-provenance.js +187 -0
  283. package/dist/utils/governance-provenance.js.map +1 -0
  284. package/dist/utils/pilot-metrics.d.ts +46 -0
  285. package/dist/utils/pilot-metrics.d.ts.map +1 -0
  286. package/dist/utils/pilot-metrics.js +240 -0
  287. package/dist/utils/pilot-metrics.js.map +1 -0
  288. package/dist/utils/policy-compiler.d.ts +6 -0
  289. package/dist/utils/policy-compiler.d.ts.map +1 -1
  290. package/dist/utils/policy-compiler.js +20 -0
  291. package/dist/utils/policy-compiler.js.map +1 -1
  292. package/dist/utils/replay-runtime.d.ts +34 -0
  293. package/dist/utils/replay-runtime.d.ts.map +1 -1
  294. package/dist/utils/replay-runtime.js +207 -0
  295. package/dist/utils/replay-runtime.js.map +1 -1
  296. package/dist/workspace/cross-repo-graph.d.ts +111 -0
  297. package/dist/workspace/cross-repo-graph.d.ts.map +1 -0
  298. package/dist/workspace/cross-repo-graph.js +450 -0
  299. package/dist/workspace/cross-repo-graph.js.map +1 -0
  300. package/dist/workspace/federated-context.d.ts +144 -0
  301. package/dist/workspace/federated-context.d.ts.map +1 -0
  302. package/dist/workspace/federated-context.js +347 -0
  303. package/dist/workspace/federated-context.js.map +1 -0
  304. package/dist/workspace/index.d.ts +38 -0
  305. package/dist/workspace/index.d.ts.map +1 -0
  306. package/dist/workspace/index.js +48 -0
  307. package/dist/workspace/index.js.map +1 -0
  308. package/package.json +10 -10
@@ -67,6 +67,14 @@ const policy_compiler_1 = require("../utils/policy-compiler");
67
67
  const change_contract_1 = require("../utils/change-contract");
68
68
  const diff_symbols_1 = require("../utils/diff-symbols");
69
69
  const advisory_signals_1 = require("../utils/advisory-signals");
70
+ const structural_rules_1 = require("../structural-rules");
71
+ const canonical_pipeline_1 = require("../governance/canonical-pipeline");
72
+ const structural_on_diff_1 = require("../governance/structural-on-diff");
73
+ const structural_policy_merge_1 = require("../governance/structural-policy-merge");
74
+ const telemetry_1 = require("@neurcode-ai/telemetry");
75
+ const governance_provenance_1 = require("../utils/governance-provenance");
76
+ const pilot_metrics_1 = require("../utils/pilot-metrics");
77
+ const explainability_1 = require("../explainability");
70
78
  const runtime_guard_1 = require("../utils/runtime-guard");
71
79
  const artifact_signature_1 = require("../utils/artifact-signature");
72
80
  const policy_1 = require("@neurcode-ai/policy");
@@ -1080,10 +1088,17 @@ function toCanonicalVerifyOutput(payload) {
1080
1088
  'policyDecision',
1081
1089
  'policyPack',
1082
1090
  'changeContractViolations',
1091
+ 'governanceVerification',
1092
+ 'governanceFindings',
1093
+ 'structuralViolations',
1094
+ 'structuralRulesApplied',
1095
+ 'structuralSuppressedCount',
1083
1096
  ];
1097
+ const canonicalMutable = canonical;
1084
1098
  for (const key of passthroughKeys) {
1085
- if (Object.prototype.hasOwnProperty.call(payload, key) && payload[key] !== undefined) {
1086
- canonical[key] = payload[key];
1099
+ const v = payload[key];
1100
+ if (Object.prototype.hasOwnProperty.call(payload, key) && v !== undefined && v !== null) {
1101
+ canonicalMutable[key] = v;
1087
1102
  }
1088
1103
  }
1089
1104
  // Backward-compatibility alias: older integrations and tests expect `rule`
@@ -1099,9 +1114,31 @@ function toCanonicalVerifyOutput(payload) {
1099
1114
  return canonical;
1100
1115
  }
1101
1116
  function emitCanonicalVerifyJson(payload, onEmit) {
1102
- const canonical = toCanonicalVerifyOutput(payload);
1117
+ const canonical = toCanonicalVerifyOutput((0, canonical_pipeline_1.attachCanonicalGovernance)(payload));
1103
1118
  onEmit?.(canonical);
1104
- console.log(JSON.stringify(canonical, null, 2));
1119
+ // Use sync stdout write so immediate process.exit paths do not truncate JSON.
1120
+ const serialized = Buffer.from(`${JSON.stringify(canonical, null, 2)}\n`, 'utf-8');
1121
+ try {
1122
+ let offset = 0;
1123
+ while (offset < serialized.length) {
1124
+ try {
1125
+ const written = (0, fs_1.writeSync)(1, serialized, offset, serialized.length - offset);
1126
+ if (written <= 0)
1127
+ break;
1128
+ offset += written;
1129
+ }
1130
+ catch (error) {
1131
+ const code = error.code;
1132
+ if (code === 'EAGAIN' || code === 'EWOULDBLOCK') {
1133
+ continue;
1134
+ }
1135
+ throw error;
1136
+ }
1137
+ }
1138
+ }
1139
+ catch {
1140
+ process.stdout.write(serialized.toString('utf-8'));
1141
+ }
1105
1142
  }
1106
1143
  function buildDeterministicLayerSummary(payload) {
1107
1144
  const verdict = asStringValue(payload.verdict) || 'UNKNOWN';
@@ -1894,6 +1931,8 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1894
1931
  message: `Policy audit chain is invalid: ${auditIntegrityStatus.issues.join('; ') || 'unknown issue'}`,
1895
1932
  });
1896
1933
  }
1934
+ const policyOnlyStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFilesForPolicy);
1935
+ (0, structural_policy_merge_1.mergeStructuralIntoPolicyViolations)(policyViolations, policyOnlyStructural.violations);
1897
1936
  policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
1898
1937
  const effectiveVerdict = policyDecision === 'block' ? 'FAIL' : policyDecision === 'warn' ? 'WARN' : 'PASS';
1899
1938
  const grade = effectiveVerdict === 'PASS' ? 'A' : effectiveVerdict === 'WARN' ? 'C' : 'F';
@@ -1962,6 +2001,9 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1962
2001
  plannedFilesModified: 0,
1963
2002
  totalPlannedFiles: 0,
1964
2003
  adherenceScore: score,
2004
+ structuralViolations: policyOnlyStructural.violations,
2005
+ structuralRulesApplied: policyOnlyStructural.rulesApplied,
2006
+ structuralSuppressedCount: policyOnlyStructural.suppressedCount,
1965
2007
  mode: 'policy_only',
1966
2008
  policyOnly: true,
1967
2009
  policyOnlySource: source,
@@ -2045,6 +2087,8 @@ async function verifyCommand(options) {
2045
2087
  const evidenceEnabled = options.evidence === true || isEnabledFlag(process.env.NEURCODE_VERIFY_EVIDENCE);
2046
2088
  const verifyStartedAtMs = Date.now();
2047
2089
  const evidenceCiContext = collectCIContext();
2090
+ /** Set when provenance is written (human path); JSON early-exit may leave null. */
2091
+ let lastProvenanceRunId = null;
2048
2092
  let lastCanonicalOutput = null;
2049
2093
  let lastEvidenceFallbackOutput = null;
2050
2094
  let evidenceFinalizeAttempted = false;
@@ -2098,6 +2142,12 @@ async function verifyCommand(options) {
2098
2142
  };
2099
2143
  const exitWithEvidence = (exitCode) => {
2100
2144
  finalizeEvidence(exitCode);
2145
+ try {
2146
+ (0, telemetry_1.appendVerifyCompletedFromCanonical)(projectRoot, lastCanonicalOutput, lastProvenanceRunId);
2147
+ }
2148
+ catch {
2149
+ // calibration must never affect exit
2150
+ }
2101
2151
  process.exit(exitCode);
2102
2152
  };
2103
2153
  exitWithEvidenceFromTry = exitWithEvidence;
@@ -2108,6 +2158,10 @@ async function verifyCommand(options) {
2108
2158
  let intentEngineSummary = null;
2109
2159
  let intentEngineFlowIssues = [];
2110
2160
  let intentEngineRegressions = [];
2161
+ // Structural rule engine results — AST-level deterministic violations
2162
+ let structuralViolations = [];
2163
+ let structuralRulesApplied = [];
2164
+ let structuralSuppressedCount = 0;
2111
2165
  const emitVerifyJson = (payload) => {
2112
2166
  const enrichedPayload = {
2113
2167
  ...payload,
@@ -2121,6 +2175,9 @@ async function verifyCommand(options) {
2121
2175
  flowIssues: payload.flowIssues ?? intentEngineFlowIssues,
2122
2176
  // V6: regressions always injected
2123
2177
  regressions: payload.regressions ?? intentEngineRegressions,
2178
+ structuralViolations: payload.structuralViolations ?? structuralViolations,
2179
+ structuralRulesApplied: payload.structuralRulesApplied ?? structuralRulesApplied,
2180
+ structuralSuppressedCount: payload.structuralSuppressedCount ?? structuralSuppressedCount,
2124
2181
  };
2125
2182
  lastEvidenceFallbackOutput = enrichedPayload;
2126
2183
  emitCanonicalVerifyJson(enrichedPayload, (canonical) => {
@@ -2439,10 +2496,14 @@ async function verifyCommand(options) {
2439
2496
  console.log(chalk.dim(' CI mode: deterministic local verification enabled (policy-only, non-interactive).'));
2440
2497
  }
2441
2498
  }
2442
- const enforceCompatibilityHandshake = isEnabledFlag(process.env.NEURCODE_VERIFY_ENFORCE_COMPAT_HANDSHAKE)
2443
- || strictArtifactMode
2444
- || (process.env.CI === 'true' && Boolean(config.apiKey));
2445
- if (config.apiKey && config.apiUrl) {
2499
+ // NEURCODE_VERIFY_LOCAL_ONLY=1 or --local-only: skip API entirely, run structural-only
2500
+ const localOnlyMode = isEnabledFlag(process.env.NEURCODE_VERIFY_LOCAL_ONLY)
2501
+ || options.localOnly === true;
2502
+ const enforceCompatibilityHandshake = !localOnlyMode
2503
+ && (isEnabledFlag(process.env.NEURCODE_VERIFY_ENFORCE_COMPAT_HANDSHAKE)
2504
+ || strictArtifactMode
2505
+ || (process.env.CI === 'true' && Boolean(config.apiKey)));
2506
+ if (!localOnlyMode && config.apiKey && config.apiUrl) {
2446
2507
  const compatibilityProbe = await probeApiRuntimeCompatibility(config.apiUrl);
2447
2508
  if (compatibilityProbe.status !== 'ok' && enforceCompatibilityHandshake) {
2448
2509
  const failureMessages = compatibilityProbe.messages.length > 0
@@ -2471,6 +2532,7 @@ async function verifyCommand(options) {
2471
2532
  mode: 'runtime_compatibility_failed',
2472
2533
  policyOnly: options.policyOnly === true,
2473
2534
  changeContract: changeContractSummary,
2535
+ offlineFallbackHint: 'Run with NEURCODE_VERIFY_LOCAL_ONLY=1 or --local-only for offline structural verification.',
2474
2536
  ...(compiledPolicyMetadata ? { policyCompilation: compiledPolicyMetadata } : {}),
2475
2537
  });
2476
2538
  }
@@ -2485,6 +2547,7 @@ async function verifyCommand(options) {
2485
2547
  }
2486
2548
  console.log(chalk.dim(` CLI version: ${CLI_COMPONENT_VERSION}`));
2487
2549
  console.log(chalk.dim(' Upgrade/downgrade CLI, Action, or API to satisfy the runtime compatibility contract before running verify.\n'));
2550
+ console.log(chalk.dim(' Tip: Use --local-only to run offline deterministic structural verification without the API.\n'));
2488
2551
  }
2489
2552
  exitWithEvidence(2);
2490
2553
  }
@@ -2704,6 +2767,62 @@ async function verifyCommand(options) {
2704
2767
  const excludeOldPath = file.oldPath ? isExcludedFile(file.oldPath) : false;
2705
2768
  return !excludePath && !excludeOldPath;
2706
2769
  });
2770
+ // ── Local-only mode (Part 8): run structural analysis and exit, no API calls ──
2771
+ // Triggered by NEURCODE_VERIFY_LOCAL_ONLY=1 or --local-only.
2772
+ // Deterministic structural governance MUST work offline, with zero API dependency.
2773
+ if (localOnlyMode) {
2774
+ if (!options.json) {
2775
+ console.log(chalk.cyan('\n🔍 Local-only mode: deterministic structural verification (no API required)...'));
2776
+ }
2777
+ const localStructural = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFiles);
2778
+ const blockingViolations = localStructural.violations.filter((v) => v.severity === 'BLOCKING');
2779
+ const localVerdict = blockingViolations.length > 0 ? 'FAIL' : 'PASS';
2780
+ const localGrade = blockingViolations.length > 0 ? 'F' : 'B';
2781
+ const localScore = blockingViolations.length > 0 ? 0 : 70;
2782
+ if (options.json) {
2783
+ emitVerifyJson({
2784
+ grade: localGrade,
2785
+ score: localScore,
2786
+ verdict: localVerdict,
2787
+ violations: localStructural.violations.map((v) => ({
2788
+ file: v.filePath,
2789
+ rule: v.ruleId,
2790
+ severity: v.severity === 'BLOCKING' ? 'block' : 'warn',
2791
+ message: `${v.ruleName}: ${v.evidence.slice(0, 120)}`,
2792
+ })),
2793
+ adherenceScore: localScore,
2794
+ bloatCount: 0,
2795
+ bloatFiles: [],
2796
+ plannedFilesModified: 0,
2797
+ totalPlannedFiles: 0,
2798
+ message: `Local-only structural verification: ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking.`,
2799
+ scopeGuardPassed: true,
2800
+ mode: 'local_only_structural',
2801
+ policyOnly: true,
2802
+ structuralViolations: localStructural.violations,
2803
+ structuralBlockingCount: blockingViolations.length,
2804
+ structuralRulesApplied: localStructural.rulesApplied,
2805
+ changeContract: changeContractSummary,
2806
+ });
2807
+ }
2808
+ else {
2809
+ if (localStructural.violations.length === 0) {
2810
+ console.log(chalk.green('\n✅ No structural violations found (local-only mode).'));
2811
+ }
2812
+ else {
2813
+ localStructural.violations.forEach((v) => {
2814
+ const prefix = v.severity === 'BLOCKING' ? chalk.red(' ⛔ BLOCKING') : chalk.yellow(' ⚠ ADVISORY');
2815
+ console.log(`${prefix} ${v.ruleId} — ${v.filePath}:${v.line}`);
2816
+ console.log(chalk.dim(` ${v.ruleName}`));
2817
+ console.log(chalk.dim(` ${v.evidence.slice(0, 100)}`));
2818
+ });
2819
+ }
2820
+ console.log(chalk.dim(`\n[Local-only] ${localStructural.violations.length} finding(s), ${blockingViolations.length} blocking. ` +
2821
+ `Remove --local-only for full governance verification.\n`));
2822
+ }
2823
+ recordVerifyEvent(localVerdict, `local_only;structural=${localStructural.violations.length}`, diffFiles.map((f) => f.path));
2824
+ exitWithEvidence(blockingViolations.length > 0 ? 2 : 0);
2825
+ }
2707
2826
  const summary = (0, diff_parser_1.getDiffSummary)(diffFiles);
2708
2827
  if (diffFiles.length === 0) {
2709
2828
  if (!options.json) {
@@ -3102,15 +3221,50 @@ async function verifyCommand(options) {
3102
3221
  summary,
3103
3222
  });
3104
3223
  const advisoryWarnCount = advisorySignals.filter((item) => item.severity === 'warn').length;
3105
- const advisoryVerdict = advisoryWarnCount > 0 ? 'WARN' : 'PASS';
3106
- const advisoryGrade = advisoryWarnCount > 0 ? 'C' : 'B';
3107
- const advisoryScore = advisoryWarnCount > 0 ? 60 : 70;
3108
- const advisoryViolations = advisorySignals.map((item) => ({
3109
- file: item.files[0] || '.',
3110
- rule: `advisory:${item.code.toLowerCase()}`,
3111
- severity: item.severity === 'warn' ? 'warn' : 'allow',
3112
- message: `${item.title}: ${item.detail}`,
3113
- }));
3224
+ // ── Advisory-first: always run structural rules, downgrade scope issues to advisory ──
3225
+ // Structural rules are deterministic and local they MUST always run regardless of plan.
3226
+ let advisoryStructuralViolations = [];
3227
+ let advisoryStructuralBlockingCount = 0;
3228
+ try {
3229
+ if (!options.json) {
3230
+ console.log(chalk.cyan('🔍 Running deterministic structural analysis (advisory mode — no plan)...'));
3231
+ }
3232
+ const structuralResult = (0, structural_on_diff_1.runStructuralOnDiffFiles)(projectRoot, diffFiles);
3233
+ advisoryStructuralViolations = structuralResult.violations;
3234
+ // In advisory mode (no plan), BLOCKING structural violations are downgraded to advisory warnings.
3235
+ // They are still surfaced — engineers must review them — but they do not block the verify exit.
3236
+ advisoryStructuralBlockingCount = structuralResult.violations.filter((v) => v.severity === 'BLOCKING').length;
3237
+ if (!options.json && advisoryStructuralViolations.length > 0) {
3238
+ console.log(chalk.yellow(`\n⚠ Structural findings (advisory — link a plan to enable enforcement):`));
3239
+ advisoryStructuralViolations.forEach((v) => {
3240
+ const prefix = v.severity === 'BLOCKING' ? chalk.yellow(' ⚠ BLOCKING (advisory)') : chalk.dim(' ℹ ADVISORY');
3241
+ console.log(`${prefix} ${v.ruleId} — ${v.filePath}:${v.line}`);
3242
+ console.log(chalk.dim(` ${v.ruleName}`));
3243
+ console.log(chalk.dim(` ${v.evidence.slice(0, 100)}`));
3244
+ });
3245
+ console.log(chalk.dim(`\n To enforce these findings: run \`neurcode plan "<intent>"\` to link a plan.\n`));
3246
+ }
3247
+ }
3248
+ catch {
3249
+ // Structural engine failure must never block advisory verify
3250
+ }
3251
+ const advisoryVerdict = advisoryWarnCount > 0 || advisoryStructuralBlockingCount > 0 ? 'WARN' : 'PASS';
3252
+ const advisoryGrade = advisoryWarnCount > 0 || advisoryStructuralBlockingCount > 0 ? 'C' : 'B';
3253
+ const advisoryScore = advisoryWarnCount > 0 || advisoryStructuralBlockingCount > 0 ? 60 : 70;
3254
+ const advisoryViolations = [
3255
+ ...advisorySignals.map((item) => ({
3256
+ file: item.files[0] || '.',
3257
+ rule: `advisory:${item.code.toLowerCase()}`,
3258
+ severity: item.severity === 'warn' ? 'warn' : 'allow',
3259
+ message: `${item.title}: ${item.detail}`,
3260
+ })),
3261
+ ...advisoryStructuralViolations.map((v) => ({
3262
+ file: v.filePath,
3263
+ rule: `structural-advisory:${v.ruleId.toLowerCase()}`,
3264
+ severity: 'warn',
3265
+ message: `${v.ruleId} ${v.ruleName}: ${v.evidence.slice(0, 100)} (advisory — link plan to enforce)`,
3266
+ })),
3267
+ ];
3114
3268
  recordVerifyEvent(advisoryVerdict, `advisory_missing_plan;signals=${advisorySignals.length};warn=${advisoryWarnCount}`, diffFiles.map((f) => f.path));
3115
3269
  if (options.json) {
3116
3270
  emitVerifyJson({
@@ -3128,6 +3282,11 @@ async function verifyCommand(options) {
3128
3282
  mode: 'advisory_missing_plan',
3129
3283
  advisoryMode: true,
3130
3284
  advisorySignals,
3285
+ structuralViolations: advisoryStructuralViolations,
3286
+ structuralBlockingCount: advisoryStructuralBlockingCount,
3287
+ structuralNote: advisoryStructuralBlockingCount > 0
3288
+ ? `${advisoryStructuralBlockingCount} structural finding(s) surfaced in advisory mode. Link a plan to enforce.`
3289
+ : undefined,
3131
3290
  policyOnly: true,
3132
3291
  policyOnlySource: 'fallback_missing_plan',
3133
3292
  ...(autoContractPath
@@ -3233,6 +3392,36 @@ async function verifyCommand(options) {
3233
3392
  // Non-fatal: intent engine errors must never break verification
3234
3393
  }
3235
3394
  }
3395
+ // ── Structural Rule Engine ──────────────────────────────────────────────
3396
+ // AST-level deterministic analysis against changed files.
3397
+ // Reads file contents from disk; never throws — errors are isolated per file.
3398
+ if (diffFiles.length > 0) {
3399
+ try {
3400
+ const structuralEngine = (0, structural_rules_1.createDefaultStructuralRuleEngine)();
3401
+ const filesToAnalyze = [];
3402
+ for (const df of diffFiles) {
3403
+ const absPath = (0, path_1.join)(projectRoot, df.path);
3404
+ if ((0, fs_1.existsSync)(absPath)) {
3405
+ try {
3406
+ const sourceText = (0, fs_1.readFileSync)(absPath, 'utf-8');
3407
+ filesToAnalyze.push({ filePath: df.path, sourceText });
3408
+ }
3409
+ catch {
3410
+ // Skip unreadable files
3411
+ }
3412
+ }
3413
+ }
3414
+ if (filesToAnalyze.length > 0) {
3415
+ const structuralResult = structuralEngine.analyze(filesToAnalyze);
3416
+ structuralViolations = structuralResult.violations;
3417
+ structuralRulesApplied = structuralResult.rulesApplied;
3418
+ structuralSuppressedCount = structuralResult.suppressedCount;
3419
+ }
3420
+ }
3421
+ catch {
3422
+ // Non-fatal: structural engine errors must never break verification
3423
+ }
3424
+ }
3236
3425
  governanceResult = (0, governance_1.evaluateGovernance)({
3237
3426
  projectRoot,
3238
3427
  task: governanceTask,
@@ -3782,6 +3971,7 @@ async function verifyCommand(options) {
3782
3971
  message: `Policy audit chain is invalid: ${auditIntegrityStatus.issues.join('; ') || 'unknown issue'}`,
3783
3972
  });
3784
3973
  }
3974
+ (0, structural_policy_merge_1.mergeStructuralIntoPolicyViolations)(policyViolations, structuralViolations);
3785
3975
  policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
3786
3976
  const policyExceptionsSummary = {
3787
3977
  sourceMode: policyExceptionResolution.mode,
@@ -4229,6 +4419,9 @@ async function verifyCommand(options) {
4229
4419
  plannedFilesModified: verifyResult.plannedFilesModified,
4230
4420
  totalPlannedFiles: verifyResult.totalPlannedFiles,
4231
4421
  verificationSource: verifySource,
4422
+ structuralViolations,
4423
+ structuralRulesApplied,
4424
+ structuralSuppressedCount,
4232
4425
  mode: 'plan_enforced',
4233
4426
  policyOnly: false,
4234
4427
  aiDebt: aiDebtSummary,
@@ -4300,7 +4493,7 @@ async function verifyCommand(options) {
4300
4493
  message: effectiveMessage,
4301
4494
  bloatFiles: displayBloatFiles,
4302
4495
  bloatCount: displayBloatFiles.length,
4303
- }, policyViolations, expediteModeEnabled, intentEngineIssues, intentEngineSummary, intentEngineFlowIssues, intentEngineRegressions);
4496
+ }, policyViolations, expediteModeEnabled, intentEngineIssues, intentEngineSummary, intentEngineFlowIssues, intentEngineRegressions, structuralViolations);
4304
4497
  if (governanceResult) {
4305
4498
  displayGovernanceInsights(governanceResult, { explain: options.explain });
4306
4499
  }
@@ -4364,6 +4557,58 @@ async function verifyCommand(options) {
4364
4557
  }
4365
4558
  }
4366
4559
  }
4560
+ // ── Governance Provenance Chain + Pilot Metrics ───────────────────────
4561
+ // Best-effort: never throws, never changes the verification outcome.
4562
+ try {
4563
+ const structuralBlocking = structuralViolations.filter(v => v.severity === 'BLOCKING').length;
4564
+ const structuralAdvisory = structuralViolations.filter(v => v.severity === 'ADVISORY').length;
4565
+ const deterministicSigs = structuralViolations.filter(v => v.determinism === 'deterministic-structural').length;
4566
+ const heuristicSigs = structuralViolations.filter(v => v.determinism === 'heuristic-advisory').length;
4567
+ const trustScore = structuralViolations.length > 0
4568
+ ? Math.round((deterministicSigs / structuralViolations.length) * 100)
4569
+ : 100;
4570
+ const prov = (0, governance_provenance_1.buildProvenanceRecord)({
4571
+ repoRoot: projectRoot,
4572
+ filesAnalyzed: diffFiles.length,
4573
+ diffContext: `${options.base || 'HEAD'} vs working tree`,
4574
+ planId: finalPlanId || null,
4575
+ intentHash: null,
4576
+ policyHash: null,
4577
+ ruleIds: structuralRulesApplied,
4578
+ blockingCount: policyViolations.filter((v) => v.severity === 'block').length + structuralBlocking,
4579
+ advisoryCount: policyViolations.filter((v) => v.severity !== 'block').length + structuralAdvisory,
4580
+ suppressedCount: structuralSuppressedCount,
4581
+ structuralBlockingCount: structuralBlocking,
4582
+ structuralAdvisoryCount: structuralAdvisory,
4583
+ deterministicSignals: deterministicSigs,
4584
+ heuristicSignals: heuristicSigs,
4585
+ overallTrustScore: trustScore,
4586
+ verdict: effectiveVerdict,
4587
+ governanceDecision: governanceResult?.governanceDecision?.summary || 'automatic',
4588
+ });
4589
+ (0, governance_provenance_1.saveProvenanceRecord)(projectRoot, prov);
4590
+ lastProvenanceRunId = prov.runId;
4591
+ // Tally per-rule counts for pilot metrics
4592
+ const ruleCounts = {};
4593
+ for (const v of structuralViolations) {
4594
+ ruleCounts[v.ruleId] = (ruleCounts[v.ruleId] ?? 0) + 1;
4595
+ }
4596
+ (0, pilot_metrics_1.recordVerifyRun)(projectRoot, {
4597
+ planCount: 0,
4598
+ verifyCount: 1,
4599
+ passCount: effectiveVerdict === 'PASS' ? 1 : 0,
4600
+ failCount: effectiveVerdict === 'FAIL' ? 1 : 0,
4601
+ blockingCaught: prov.blockingCount,
4602
+ advisoryCaught: prov.advisoryCount,
4603
+ suppressions: structuralSuppressedCount,
4604
+ structuralCaught: structuralViolations.length,
4605
+ aiDebtDelta: aiDebtSummary?.score ?? 0,
4606
+ ruleCounts,
4607
+ });
4608
+ }
4609
+ catch {
4610
+ // Never break verification
4611
+ }
4367
4612
  // Report to Neurcode Cloud if --record flag is set
4368
4613
  const filteredBloatForReport = (verifyResult.bloatFiles || []).filter((f) => !shouldIgnore(f));
4369
4614
  const reportViolations = [
@@ -4833,7 +5078,7 @@ function displayChangeContractDrift(summary, options = { advisory: false }) {
4833
5078
  /**
4834
5079
  * Display verification results in a formatted report card
4835
5080
  */
4836
- function displayVerifyResults(result, policyViolations, expediteModeUsed = false, intentIssuesForDisplay = [], intentSummaryForDisplay = null, flowIssuesForDisplay = [], regressionsForDisplay = []) {
5081
+ function displayVerifyResults(result, policyViolations, expediteModeUsed = false, intentIssuesForDisplay = [], intentSummaryForDisplay = null, flowIssuesForDisplay = [], regressionsForDisplay = [], structuralViolationsForDisplay = []) {
4837
5082
  // ── Header ────────────────────────────────────────────────────────────────
4838
5083
  const headerLabel = result.verdict === 'PASS'
4839
5084
  ? chalk.bold.green('\n✅ VERIFICATION PASSED')
@@ -4915,6 +5160,19 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
4915
5160
  policy: item.rule || 'policy_violation',
4916
5161
  severity: item.severity,
4917
5162
  }));
5163
+ // Structural rule violations — split by severity
5164
+ const structuralBlocking = structuralViolationsForDisplay
5165
+ .filter((v) => v.severity === 'BLOCKING')
5166
+ .map((v) => ({
5167
+ file: v.filePath,
5168
+ message: `${v.ruleId} · ${v.ruleName} (line ${v.line}) — ${v.operationalRisk}`,
5169
+ }));
5170
+ const structuralAdvisory = structuralViolationsForDisplay
5171
+ .filter((v) => v.severity === 'ADVISORY')
5172
+ .map((v) => ({
5173
+ file: v.filePath,
5174
+ message: `${v.ruleId} · ${v.ruleName} (line ${v.line}) — ${v.operationalRisk}`,
5175
+ }));
4918
5176
  let blockingItems = [
4919
5177
  ...scopeItems.map((item) => ({
4920
5178
  file: item.file,
@@ -4926,13 +5184,17 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
4926
5184
  file: item.file,
4927
5185
  message: item.message,
4928
5186
  })),
5187
+ ...structuralBlocking,
5188
+ ];
5189
+ let advisoryItems = [
5190
+ ...policyTriageItems
5191
+ .filter((item) => !isBlockingSeverity(item.severity))
5192
+ .map((item) => ({
5193
+ file: item.file,
5194
+ message: item.message,
5195
+ })),
5196
+ ...structuralAdvisory,
4929
5197
  ];
4930
- let advisoryItems = policyTriageItems
4931
- .filter((item) => !isBlockingSeverity(item.severity))
4932
- .map((item) => ({
4933
- file: item.file,
4934
- message: item.message,
4935
- }));
4936
5198
  let expediteItems = [];
4937
5199
  if (expediteModeUsed) {
4938
5200
  blockingItems = [
@@ -5044,6 +5306,49 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
5044
5306
  });
5045
5307
  console.log(chalk.bold.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
5046
5308
  }
5309
+ // ── Structural Rule Engine ─────────────────────────────────────────────────
5310
+ // Display detailed structural violations with AST evidence and determinism labels.
5311
+ if (structuralViolationsForDisplay.length > 0) {
5312
+ try {
5313
+ const report = (0, explainability_1.buildViolationReport)(structuralViolationsForDisplay, '');
5314
+ const formatter = new explainability_1.ViolationFormatter();
5315
+ const blocking = report.blocking;
5316
+ const advisory = report.advisory;
5317
+ if (blocking.length > 0 || advisory.length > 0) {
5318
+ console.log(chalk.bold('\n━━━ STRUCTURAL ANALYSIS ━━━━━━━━━━━━━━━━━'));
5319
+ blocking.slice(0, 5).forEach((v) => {
5320
+ const detLabel = v.determinism === 'deterministic-structural'
5321
+ ? chalk.cyan('⚙ AST-verified')
5322
+ : chalk.yellow('⚡ heuristic');
5323
+ console.log(chalk.red(`\n ● ${v.ruleId} [BLOCKING] ${detLabel} · confidence ${Math.round(v.confidence * 100)}%`));
5324
+ console.log(chalk.bold(` ${v.filePath}:${v.line}`));
5325
+ console.log(chalk.dim(` Pattern: ${v.evidence.matchReason}`));
5326
+ if (v.evidence.codeSnippet) {
5327
+ console.log(chalk.dim(` Code: ${v.evidence.codeSnippet.slice(0, 100)}`));
5328
+ }
5329
+ console.log(chalk.yellow(` Risk: ${v.operationalRisk}`));
5330
+ console.log(chalk.green(` Fix: ${v.remediation}`));
5331
+ });
5332
+ if (blocking.length > 5) {
5333
+ console.log(chalk.dim(`\n ... ${blocking.length - 5} more blocking structural violations`));
5334
+ }
5335
+ advisory.slice(0, 3).forEach((v) => {
5336
+ console.log(chalk.yellow(`\n ○ ${v.ruleId} [ADVISORY] ⚡ heuristic · confidence ${Math.round(v.confidence * 100)}%`));
5337
+ console.log(chalk.dim(` ${v.filePath}:${v.line} — ${v.operationalRisk}`));
5338
+ });
5339
+ if (advisory.length > 3) {
5340
+ console.log(chalk.dim(` ... ${advisory.length - 3} more advisory structural violations`));
5341
+ }
5342
+ const deterministicCount = report.deterministicCount;
5343
+ const heuristicCount = report.heuristicCount;
5344
+ console.log(chalk.dim(`\n Determinism: ${deterministicCount} AST-verified · ${heuristicCount} heuristic`));
5345
+ console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
5346
+ }
5347
+ }
5348
+ catch {
5349
+ // Non-fatal: explainability rendering must never break verification display
5350
+ }
5351
+ }
5047
5352
  const hasAnyIssue = blockingItems.length > 0 ||
5048
5353
  advisoryItems.length > 0 ||
5049
5354
  expediteItems.length > 0 ||
@@ -5084,6 +5389,12 @@ function printAdvisorySignals(signals, demoMode) {
5084
5389
  const severityLabel = signal.severity === 'warn' ? chalk.yellow('[warn]') : chalk.dim('[info]');
5085
5390
  console.log(`${severityLabel} ${signal.title}`);
5086
5391
  console.log(chalk.dim(` ${signal.detail}`));
5392
+ console.log(chalk.dim(` Confidence: ${signal.confidence.toUpperCase()} (advisory-only)`));
5393
+ if (signal.evidence.length > 0) {
5394
+ console.log(chalk.dim(` Evidence: ${signal.evidence.join(', ')}`));
5395
+ }
5396
+ console.log(chalk.dim(` Structural gap: ${signal.structuralCoverageGap}`));
5397
+ console.log(chalk.dim(` Uncertainty: ${signal.uncertainty}`));
5087
5398
  signal.files.forEach((file) => {
5088
5399
  console.log(chalk.dim(` - ${file}`));
5089
5400
  });