mirai-graph 1.0.0-rc.1

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 (432) hide show
  1. package/CHANGELOG.md +376 -0
  2. package/CITATION.cff +20 -0
  3. package/LICENSE +21 -0
  4. package/LICENSE-DOCS +26 -0
  5. package/README.md +270 -0
  6. package/ROADMAP.md +225 -0
  7. package/benchmarks/protocols/measure-convert-optimize.md +131 -0
  8. package/benchmarks/synthetic-context-reduction-v0/README.md +70 -0
  9. package/benchmarks/synthetic-context-reduction-v0/RESULT.md +52 -0
  10. package/benchmarks/synthetic-context-reduction-v0/expected/context-pack-compact.md +31 -0
  11. package/benchmarks/synthetic-context-reduction-v0/gates/results.json +12 -0
  12. package/benchmarks/synthetic-context-reduction-v0/graph/objects.json +114 -0
  13. package/benchmarks/synthetic-context-reduction-v0/graph/relations.json +74 -0
  14. package/benchmarks/synthetic-context-reduction-v0/metrics/example-metrics.json +22 -0
  15. package/benchmarks/synthetic-context-reduction-v0/mirai-graph-package.json +14 -0
  16. package/benchmarks/synthetic-context-reduction-v0/results/baseline-comparison-result.json +42 -0
  17. package/benchmarks/synthetic-context-reduction-v0/results/context-pack.json +181 -0
  18. package/benchmarks/synthetic-context-reduction-v0/results/context-reduction-result.json +8 -0
  19. package/benchmarks/synthetic-context-reduction-v0/results/profile-conformance-result.json +28 -0
  20. package/benchmarks/synthetic-context-reduction-v0/results/readiness-score.json +24 -0
  21. package/benchmarks/synthetic-context-reduction-v0/reviews/semantic-completeness-review.json +78 -0
  22. package/benchmarks/synthetic-context-reduction-v0/scripts/calculate-context-reduction.js +42 -0
  23. package/benchmarks/synthetic-context-reduction-v0/source-corpus/audit-events.md +8 -0
  24. package/benchmarks/synthetic-context-reduction-v0/source-corpus/content-workflow.md +8 -0
  25. package/benchmarks/synthetic-context-reduction-v0/source-corpus/identity-access.md +8 -0
  26. package/benchmarks/synthetic-context-reduction-v0/source-corpus/notification-delivery.md +8 -0
  27. package/benchmarks/synthetic-context-reduction-v0/tasks/tasks.json +31 -0
  28. package/docs/adoption/adopter-kit.md +179 -0
  29. package/docs/adoption/ai-employee-graph.md +151 -0
  30. package/docs/adoption/character-layer.md +196 -0
  31. package/docs/adoption/choose-profile.md +98 -0
  32. package/docs/adoption/cli.md +78 -0
  33. package/docs/adoption/developer-integration-guide.md +93 -0
  34. package/docs/adoption/end-to-end-control-loop.md +168 -0
  35. package/docs/adoption/getting-started.md +169 -0
  36. package/docs/adoption/mirai-graph-transition.md +64 -0
  37. package/docs/adoption/profile-conformance-fixtures.md +112 -0
  38. package/docs/adoption/seed-to-validated-package.md +121 -0
  39. package/docs/concept.md +109 -0
  40. package/docs/repository-purpose.md +421 -0
  41. package/docs/research/ai-work-field-instrumentation-bridge.md +126 -0
  42. package/docs/research/baseline-comparison-protocol.md +79 -0
  43. package/docs/research/evidence-package-v0.1.md +99 -0
  44. package/docs/research/evidence-package-v0.2.md +150 -0
  45. package/docs/research/evidence-package-v0.3.md +226 -0
  46. package/docs/research/independent-implementation-pilot-plan.md +74 -0
  47. package/docs/research/limitations-and-threats.md +40 -0
  48. package/docs/research/practice-science-program.md +232 -0
  49. package/docs/research/scientific-evidence-package.md +154 -0
  50. package/docs/research/semantic-completeness-review-protocol.md +70 -0
  51. package/docs/terminology.md +119 -0
  52. package/docs/transfer/ai-employee-profile-proposal.md +119 -0
  53. package/docs/transfer/federation-routing-control-loop-2026-05-31.md +28 -0
  54. package/docs/transfer/graph-capability-map-2026-05-29.md +126 -0
  55. package/docs/transfer/graph-skill-to-mirai-graph.md +128 -0
  56. package/docs/transfer/project-management-standard-harvest-2026-06-02.md +322 -0
  57. package/docs/transfer/skill-graph-standard-harvest-2026-05-31.md +113 -0
  58. package/docs/transfer/standard-gap-report-2026-05-28.md +208 -0
  59. package/examples/ai-employee-minimal/README.md +53 -0
  60. package/examples/ai-employee-minimal/gates/results.json +35 -0
  61. package/examples/ai-employee-minimal/graph/objects.json +187 -0
  62. package/examples/ai-employee-minimal/graph/relations.json +167 -0
  63. package/examples/ai-employee-minimal/mirai-graph-package.json +14 -0
  64. package/examples/ai-employee-minimal/results/profile-conformance-result.json +28 -0
  65. package/examples/character-layer-integration-minimal/README.md +25 -0
  66. package/examples/character-layer-integration-minimal/results/character-layer-integration.json +53 -0
  67. package/examples/character-layer-minimal/README.md +29 -0
  68. package/examples/character-layer-minimal/gates/results.json +57 -0
  69. package/examples/character-layer-minimal/graph/objects.json +165 -0
  70. package/examples/character-layer-minimal/graph/relations.json +178 -0
  71. package/examples/character-layer-minimal/mirai-graph-package.json +14 -0
  72. package/examples/character-layer-readiness-1-0/README.md +27 -0
  73. package/examples/character-layer-readiness-1-0/results/character-layer-readiness.json +90 -0
  74. package/examples/federation-routing-smoke/README.md +19 -0
  75. package/examples/federation-routing-smoke/federation-health-dashboard.json +42 -0
  76. package/examples/federation-routing-smoke/route-explanation.json +32 -0
  77. package/examples/federation-routing-smoke/route-regression-result.json +35 -0
  78. package/examples/federation-routing-smoke/routes/production-deploy-execution-evidence.json +17 -0
  79. package/examples/federation-routing-smoke/routes/production-deploy-route-result.json +12 -0
  80. package/examples/federation-routing-smoke/routes/production-deploy-runtime-preflight.json +8 -0
  81. package/examples/federation-routing-smoke/routes/production-deploy-stderr.txt +1 -0
  82. package/examples/federation-routing-smoke/routes/production-deploy-stdout.txt +1 -0
  83. package/examples/federation-routing-smoke/routes/search-page-execution-evidence.json +17 -0
  84. package/examples/federation-routing-smoke/routes/search-page-route-result.json +12 -0
  85. package/examples/federation-routing-smoke/routes/search-page-stderr.txt +1 -0
  86. package/examples/federation-routing-smoke/routes/search-page-stdout.txt +1 -0
  87. package/examples/federation-routing-smoke/routing-fixture-run.json +66 -0
  88. package/examples/federation-routing-smoke/routing-fixtures.json +44 -0
  89. package/examples/graph-dna-alignment-minimal/README.md +16 -0
  90. package/examples/graph-dna-alignment-minimal/graph/objects.json +38 -0
  91. package/examples/graph-dna-alignment-minimal/graph/relations.json +20 -0
  92. package/examples/graph-dna-alignment-minimal/mirai-graph-package.json +14 -0
  93. package/examples/graph-dna-alignment-minimal/results/graph-dna-alignment.json +32 -0
  94. package/examples/graph-seed-minimal/README.md +9 -0
  95. package/examples/graph-seed-minimal/graph-embryo.json +63 -0
  96. package/examples/graph-seed-minimal/graph-seed.json +60 -0
  97. package/examples/implementation-control-cycles/README.md +47 -0
  98. package/examples/implementation-control-cycles/gates/results.json +22 -0
  99. package/examples/implementation-control-cycles/graph/objects.json +119 -0
  100. package/examples/implementation-control-cycles/graph/relations.json +200 -0
  101. package/examples/implementation-control-cycles/mirai-graph-package.json +14 -0
  102. package/examples/implementation-control-cycles/results/implementation-control-cycles.json +456 -0
  103. package/examples/implementation-control-minimal/README.md +39 -0
  104. package/examples/implementation-control-minimal/gates/results.json +42 -0
  105. package/examples/implementation-control-minimal/graph/objects.json +128 -0
  106. package/examples/implementation-control-minimal/graph/relations.json +128 -0
  107. package/examples/implementation-control-minimal/mirai-graph-package.json +14 -0
  108. package/examples/implementation-control-minimal/results/implementation-control-loop.json +21 -0
  109. package/examples/instrumentation-layer-minimal/README.md +32 -0
  110. package/examples/instrumentation-layer-minimal/gates/results.json +11 -0
  111. package/examples/instrumentation-layer-minimal/graph/objects.json +74 -0
  112. package/examples/instrumentation-layer-minimal/graph/relations.json +56 -0
  113. package/examples/instrumentation-layer-minimal/invalid-cockpit-missing-gates.json +40 -0
  114. package/examples/instrumentation-layer-minimal/invalid-feedback-accepted-with-blocking.json +38 -0
  115. package/examples/instrumentation-layer-minimal/invalid-feedback-process-improvement-without-kaizen.json +38 -0
  116. package/examples/instrumentation-layer-minimal/invalid-traceability-missing-evidence.json +43 -0
  117. package/examples/instrumentation-layer-minimal/mirai-graph-package.json +14 -0
  118. package/examples/instrumentation-layer-minimal/results/development-cockpit.json +68 -0
  119. package/examples/instrumentation-layer-minimal/results/feature-implementation-traceability.json +56 -0
  120. package/examples/instrumentation-layer-minimal/results/multi-source-quality-feedback.json +72 -0
  121. package/examples/invalid-character-layer-context-authorization/graph/objects.json +22 -0
  122. package/examples/invalid-character-layer-context-authorization/graph/relations.json +1 -0
  123. package/examples/invalid-character-layer-context-authorization/mirai-graph-package.json +14 -0
  124. package/examples/invalid-character-layer-correction-loop-no-review/graph/objects.json +22 -0
  125. package/examples/invalid-character-layer-correction-loop-no-review/graph/relations.json +1 -0
  126. package/examples/invalid-character-layer-correction-loop-no-review/mirai-graph-package.json +14 -0
  127. package/examples/invalid-character-layer-feedback-auto-update/graph/objects.json +22 -0
  128. package/examples/invalid-character-layer-feedback-auto-update/graph/relations.json +1 -0
  129. package/examples/invalid-character-layer-feedback-auto-update/mirai-graph-package.json +14 -0
  130. package/examples/invalid-character-layer-object-kind/graph/objects.json +22 -0
  131. package/examples/invalid-character-layer-object-kind/graph/relations.json +1 -0
  132. package/examples/invalid-character-layer-object-kind/mirai-graph-package.json +14 -0
  133. package/examples/invalid-character-layer-relation-direction/graph/objects.json +33 -0
  134. package/examples/invalid-character-layer-relation-direction/graph/relations.json +13 -0
  135. package/examples/invalid-character-layer-relation-direction/mirai-graph-package.json +14 -0
  136. package/examples/invalid-character-layer-relation-type/graph/objects.json +33 -0
  137. package/examples/invalid-character-layer-relation-type/graph/relations.json +13 -0
  138. package/examples/invalid-character-layer-relation-type/mirai-graph-package.json +14 -0
  139. package/examples/invalid-character-layer-role-permission/graph/objects.json +22 -0
  140. package/examples/invalid-character-layer-role-permission/graph/relations.json +1 -0
  141. package/examples/invalid-character-layer-role-permission/mirai-graph-package.json +14 -0
  142. package/examples/invalid-context-pack-missing-explanation/context-pack.json +25 -0
  143. package/examples/invalid-missing-relation-target/graph/objects.json +11 -0
  144. package/examples/invalid-missing-relation-target/graph/relations.json +11 -0
  145. package/examples/invalid-missing-relation-target/mirai-graph-package.json +11 -0
  146. package/examples/invalid-profile-object-kind/graph/objects.json +20 -0
  147. package/examples/invalid-profile-object-kind/graph/relations.json +1 -0
  148. package/examples/invalid-profile-object-kind/mirai-graph-package.json +11 -0
  149. package/examples/invalid-profile-relation-type/graph/objects.json +29 -0
  150. package/examples/invalid-profile-relation-type/graph/relations.json +11 -0
  151. package/examples/invalid-profile-relation-type/mirai-graph-package.json +11 -0
  152. package/examples/invalid-relation-id-mismatch/graph/objects.json +29 -0
  153. package/examples/invalid-relation-id-mismatch/graph/relations.json +11 -0
  154. package/examples/invalid-relation-id-mismatch/mirai-graph-package.json +11 -0
  155. package/examples/invalid-seed-unsafe-write/graph-seed.json +27 -0
  156. package/examples/launch-record-minimal/README.md +29 -0
  157. package/examples/launch-record-minimal/gates/results.json +12 -0
  158. package/examples/launch-record-minimal/graph/objects.json +47 -0
  159. package/examples/launch-record-minimal/graph/relations.json +38 -0
  160. package/examples/launch-record-minimal/mirai-graph-package.json +11 -0
  161. package/examples/launch-record-minimal/results/launch-record.json +51 -0
  162. package/examples/managed-project-control-loop/README.md +43 -0
  163. package/examples/managed-project-control-loop/gates/results.json +22 -0
  164. package/examples/managed-project-control-loop/graph/objects.json +119 -0
  165. package/examples/managed-project-control-loop/graph/relations.json +110 -0
  166. package/examples/managed-project-control-loop/mirai-graph-package.json +14 -0
  167. package/examples/managed-project-control-loop/results/managed-loop-result.json +21 -0
  168. package/examples/minimal-graph/README.md +15 -0
  169. package/examples/minimal-graph/gates/results.json +12 -0
  170. package/examples/minimal-graph/graph/objects.json +24 -0
  171. package/examples/minimal-graph/graph/relations.json +11 -0
  172. package/examples/minimal-graph/mirai-graph-package.json +14 -0
  173. package/examples/minimal-graph/results/profile-conformance-result.json +26 -0
  174. package/examples/model-portability-minimal/README.md +15 -0
  175. package/examples/model-portability-minimal/results/model-portability-evidence.json +55 -0
  176. package/examples/organization-governance-minimal/README.md +29 -0
  177. package/examples/organization-governance-minimal/gates/results.json +21 -0
  178. package/examples/organization-governance-minimal/graph/objects.json +147 -0
  179. package/examples/organization-governance-minimal/graph/relations.json +147 -0
  180. package/examples/organization-governance-minimal/mirai-graph-package.json +15 -0
  181. package/examples/organization-governance-minimal/results/profile-conformance-result.json +31 -0
  182. package/examples/process-control-contract-minimal/README.md +19 -0
  183. package/examples/process-control-contract-minimal/graph/objects.json +38 -0
  184. package/examples/process-control-contract-minimal/graph/relations.json +29 -0
  185. package/examples/process-control-contract-minimal/mirai-graph-package.json +11 -0
  186. package/examples/process-control-contract-minimal/results/process-control-contract.json +58 -0
  187. package/examples/process-transition-minimal/README.md +25 -0
  188. package/examples/process-transition-minimal/invalid-missing-launch-record.json +14 -0
  189. package/examples/process-transition-minimal/invalid-ready-to-written.json +14 -0
  190. package/examples/process-transition-minimal/invalid-release-missing-evidence.json +14 -0
  191. package/examples/process-transition-minimal/invalid-sync-to-update.json +14 -0
  192. package/examples/process-transition-minimal/invalid-terminal-missing-kaizen.json +14 -0
  193. package/examples/process-transition-minimal/invalid-tests-to-approved.json +14 -0
  194. package/examples/process-transition-minimal/results/transition-explanation-invalid-ready-to-written.json +35 -0
  195. package/examples/process-transition-minimal/results/transition-explanation-valid.json +34 -0
  196. package/examples/process-transition-minimal/state-machine.json +79 -0
  197. package/examples/process-transition-minimal/transition-request-skip-kaizen.json +14 -0
  198. package/examples/process-transition-minimal/transition-request.json +14 -0
  199. package/examples/risk-and-coordination-minimal/README.md +16 -0
  200. package/examples/risk-and-coordination-minimal/graph/objects.json +47 -0
  201. package/examples/risk-and-coordination-minimal/graph/relations.json +29 -0
  202. package/examples/risk-and-coordination-minimal/mirai-graph-package.json +14 -0
  203. package/examples/risk-and-coordination-minimal/results/multi-agent-coordination.json +25 -0
  204. package/examples/risk-and-coordination-minimal/results/risk-control-matrix.json +34 -0
  205. package/examples/skill-runtime-minimal/README.md +29 -0
  206. package/examples/skill-runtime-minimal/gates/results.json +35 -0
  207. package/examples/skill-runtime-minimal/graph/objects.json +209 -0
  208. package/examples/skill-runtime-minimal/graph/relations.json +178 -0
  209. package/examples/skill-runtime-minimal/mirai-graph-package.json +14 -0
  210. package/examples/skill-runtime-minimal/results/profile-conformance-result.json +27 -0
  211. package/examples/source-boundary-minimal/README.md +16 -0
  212. package/examples/source-boundary-minimal/graph/objects.json +38 -0
  213. package/examples/source-boundary-minimal/graph/relations.json +20 -0
  214. package/examples/source-boundary-minimal/mirai-graph-package.json +14 -0
  215. package/examples/source-boundary-minimal/results/source-boundary-contract.json +37 -0
  216. package/examples/technology-quality-feedback-minimal/README.md +33 -0
  217. package/examples/technology-quality-feedback-minimal/graph/objects.json +56 -0
  218. package/examples/technology-quality-feedback-minimal/graph/relations.json +47 -0
  219. package/examples/technology-quality-feedback-minimal/invalid-accepted-with-blocking.json +33 -0
  220. package/examples/technology-quality-feedback-minimal/invalid-evidence-as-authorization.json +22 -0
  221. package/examples/technology-quality-feedback-minimal/invalid-missing-required-step.json +22 -0
  222. package/examples/technology-quality-feedback-minimal/invalid-process-improvement-without-kaizen.json +33 -0
  223. package/examples/technology-quality-feedback-minimal/invalid-spec-gap-without-route.json +33 -0
  224. package/examples/technology-quality-feedback-minimal/invalid-unclassified-finding.json +33 -0
  225. package/examples/technology-quality-feedback-minimal/mirai-graph-package.json +11 -0
  226. package/examples/technology-quality-feedback-minimal/results/technology-quality-feedback.json +80 -0
  227. package/examples/work-recovery-minimal/README.md +15 -0
  228. package/examples/work-recovery-minimal/graph/objects.json +47 -0
  229. package/examples/work-recovery-minimal/graph/relations.json +20 -0
  230. package/examples/work-recovery-minimal/mirai-graph-package.json +14 -0
  231. package/examples/work-recovery-minimal/results/recovery-resume-record.json +17 -0
  232. package/examples/work-recovery-minimal/results/work-state-machine.json +21 -0
  233. package/package.json +104 -0
  234. package/packages/cli/adopter-workflow.js +227 -0
  235. package/packages/cli/context-pack.js +267 -0
  236. package/packages/cli/instrumentation-report.js +97 -0
  237. package/packages/cli/mirai-graph.js +121 -0
  238. package/packages/cli/mirai_graph.js +3 -0
  239. package/packages/cli/playground-demo.js +114 -0
  240. package/packages/cli/readiness-score.js +162 -0
  241. package/packages/cli/release-state.js +329 -0
  242. package/packages/cli/seed-preview.js +78 -0
  243. package/packages/cli/validate-adopter-workflow.js +63 -0
  244. package/packages/cli/validate-baseline-comparison.js +105 -0
  245. package/packages/cli/validate-mirai-graph.js +2434 -0
  246. package/packages/cli/validate-process-transition-report.js +105 -0
  247. package/packages/cli/validate-profile-results.js +64 -0
  248. package/packages/cli/validate-release-state.js +100 -0
  249. package/packages/cli/validate-routing-control-examples.js +79 -0
  250. package/pilots/independent-implementation-001-conference-planning/README.md +40 -0
  251. package/pilots/independent-implementation-001-conference-planning/gates/results.json +12 -0
  252. package/pilots/independent-implementation-001-conference-planning/graph/objects.json +74 -0
  253. package/pilots/independent-implementation-001-conference-planning/graph/relations.json +56 -0
  254. package/pilots/independent-implementation-001-conference-planning/graph-seed.json +65 -0
  255. package/pilots/independent-implementation-001-conference-planning/mirai-graph-package.json +14 -0
  256. package/pilots/independent-implementation-001-conference-planning/reports/pilot-report.md +120 -0
  257. package/pilots/independent-implementation-001-conference-planning/results/context-pack.json +35 -0
  258. package/pilots/independent-implementation-001-conference-planning/results/graph-embryo.json +81 -0
  259. package/pilots/independent-implementation-001-conference-planning/results/package-validation.json +7 -0
  260. package/pilots/independent-implementation-001-conference-planning/results/profile-conformance-result.json +28 -0
  261. package/pilots/independent-implementation-001-conference-planning/results/readiness-score.json +26 -0
  262. package/pilots/independent-implementation-001-conference-planning/results/seed-validation.json +7 -0
  263. package/pilots/independent-implementation-002-software-specification/README.md +40 -0
  264. package/pilots/independent-implementation-002-software-specification/gates/results.json +22 -0
  265. package/pilots/independent-implementation-002-software-specification/graph/objects.json +101 -0
  266. package/pilots/independent-implementation-002-software-specification/graph/relations.json +92 -0
  267. package/pilots/independent-implementation-002-software-specification/graph-seed.json +72 -0
  268. package/pilots/independent-implementation-002-software-specification/mirai-graph-package.json +14 -0
  269. package/pilots/independent-implementation-002-software-specification/reports/pilot-report.md +142 -0
  270. package/pilots/independent-implementation-002-software-specification/results/context-pack.json +184 -0
  271. package/pilots/independent-implementation-002-software-specification/results/graph-embryo.json +90 -0
  272. package/pilots/independent-implementation-002-software-specification/results/package-validation.json +7 -0
  273. package/pilots/independent-implementation-002-software-specification/results/profile-conformance-result.json +28 -0
  274. package/pilots/independent-implementation-002-software-specification/results/readiness-score.json +26 -0
  275. package/pilots/independent-implementation-002-software-specification/results/seed-validation.json +7 -0
  276. package/pilots/independent-implementation-002-software-specification/reviews/semantic-completeness-review.json +81 -0
  277. package/pilots/independent-implementation-003-ai-employee-workflow/README.md +42 -0
  278. package/pilots/independent-implementation-003-ai-employee-workflow/gates/results.json +30 -0
  279. package/pilots/independent-implementation-003-ai-employee-workflow/graph/objects.json +156 -0
  280. package/pilots/independent-implementation-003-ai-employee-workflow/graph/relations.json +147 -0
  281. package/pilots/independent-implementation-003-ai-employee-workflow/graph-seed.json +90 -0
  282. package/pilots/independent-implementation-003-ai-employee-workflow/mirai-graph-package.json +15 -0
  283. package/pilots/independent-implementation-003-ai-employee-workflow/reports/pilot-report.md +49 -0
  284. package/pilots/independent-implementation-003-ai-employee-workflow/results/profile-conformance-result.json +30 -0
  285. package/pilots/independent-implementation-004-research-program/README.md +41 -0
  286. package/pilots/independent-implementation-004-research-program/gates/results.json +21 -0
  287. package/pilots/independent-implementation-004-research-program/graph/objects.json +102 -0
  288. package/pilots/independent-implementation-004-research-program/graph/relations.json +84 -0
  289. package/pilots/independent-implementation-004-research-program/graph-seed.json +76 -0
  290. package/pilots/independent-implementation-004-research-program/mirai-graph-package.json +15 -0
  291. package/pilots/independent-implementation-004-research-program/reports/pilot-report.md +50 -0
  292. package/pilots/independent-implementation-004-research-program/results/profile-conformance-result.json +30 -0
  293. package/pilots/independent-implementation-005-organization-governance/README.md +42 -0
  294. package/pilots/independent-implementation-005-organization-governance/gates/results.json +20 -0
  295. package/pilots/independent-implementation-005-organization-governance/graph/objects.json +137 -0
  296. package/pilots/independent-implementation-005-organization-governance/graph/relations.json +110 -0
  297. package/pilots/independent-implementation-005-organization-governance/graph-seed.json +97 -0
  298. package/pilots/independent-implementation-005-organization-governance/mirai-graph-package.json +14 -0
  299. package/pilots/independent-implementation-005-organization-governance/reports/pilot-report.md +47 -0
  300. package/pilots/independent-implementation-005-organization-governance/results/profile-conformance-result.json +29 -0
  301. package/playground/README.md +78 -0
  302. package/playground/demo-report.md +84 -0
  303. package/profiles/README.md +19 -0
  304. package/profiles/ai-employee/README.md +132 -0
  305. package/profiles/ai-employee/profile.json +58 -0
  306. package/profiles/character-layer/README.md +143 -0
  307. package/profiles/character-layer/profile.json +46 -0
  308. package/profiles/implementation-control/README.md +170 -0
  309. package/profiles/implementation-control/profile.json +106 -0
  310. package/profiles/organization-governance/README.md +61 -0
  311. package/profiles/organization-governance/profile.json +56 -0
  312. package/profiles/project-management/README.md +115 -0
  313. package/profiles/project-management/profile.json +31 -0
  314. package/profiles/skill-runtime/README.md +94 -0
  315. package/profiles/skill-runtime/profile.json +58 -0
  316. package/profiles/software-specification/README.md +142 -0
  317. package/profiles/software-specification/profile.json +31 -0
  318. package/publications/README.md +24 -0
  319. package/publications/preprint-note.md +11 -0
  320. package/publications/preprint-outline.md +45 -0
  321. package/releases/0.1.0-alpha.0.md +45 -0
  322. package/releases/0.1.0-alpha.1.md +63 -0
  323. package/releases/0.1.0-alpha.10.md +93 -0
  324. package/releases/0.1.0-alpha.11.md +114 -0
  325. package/releases/0.1.0-alpha.2.md +37 -0
  326. package/releases/0.1.0-alpha.3.md +61 -0
  327. package/releases/0.1.0-alpha.4.md +53 -0
  328. package/releases/0.1.0-alpha.5.md +48 -0
  329. package/releases/0.1.0-alpha.6.md +96 -0
  330. package/releases/0.1.0-alpha.7.md +114 -0
  331. package/releases/0.1.0-alpha.8.md +92 -0
  332. package/releases/0.1.0-alpha.9.md +80 -0
  333. package/releases/1.0.0-rc.1.md +112 -0
  334. package/releases/README.md +114 -0
  335. package/schemas/baseline-comparison-result.schema.json +87 -0
  336. package/schemas/character-layer-integration.schema.json +112 -0
  337. package/schemas/character-layer-readiness.schema.json +73 -0
  338. package/schemas/context-pack.schema.json +137 -0
  339. package/schemas/development-cockpit.schema.json +74 -0
  340. package/schemas/feature-implementation-traceability.schema.json +80 -0
  341. package/schemas/federation-health-dashboard.schema.json +47 -0
  342. package/schemas/gate-result.schema.json +44 -0
  343. package/schemas/graph-dna-alignment.schema.json +49 -0
  344. package/schemas/graph-embryo.schema.json +51 -0
  345. package/schemas/graph-seed.schema.json +137 -0
  346. package/schemas/implementation-control-cycle.schema.json +265 -0
  347. package/schemas/implementation-control-loop.schema.json +84 -0
  348. package/schemas/launch-record.schema.json +78 -0
  349. package/schemas/model-portability-evidence.schema.json +93 -0
  350. package/schemas/multi-agent-coordination.schema.json +35 -0
  351. package/schemas/multi-source-quality-feedback.schema.json +54 -0
  352. package/schemas/object.schema.json +49 -0
  353. package/schemas/package-manifest.schema.json +53 -0
  354. package/schemas/process-control-contract.schema.json +100 -0
  355. package/schemas/process-transition-request.schema.json +41 -0
  356. package/schemas/profile.schema.json +56 -0
  357. package/schemas/readiness-score.schema.json +43 -0
  358. package/schemas/recovery-resume-record.schema.json +25 -0
  359. package/schemas/relation.schema.json +43 -0
  360. package/schemas/risk-control-matrix.schema.json +36 -0
  361. package/schemas/route-explanation.schema.json +51 -0
  362. package/schemas/route-regression-result.schema.json +33 -0
  363. package/schemas/routing-fixture-run.schema.json +45 -0
  364. package/schemas/routing-fixtures.schema.json +59 -0
  365. package/schemas/source-boundary-contract.schema.json +31 -0
  366. package/schemas/technology-quality-feedback.schema.json +116 -0
  367. package/schemas/work-state-machine.schema.json +34 -0
  368. package/standard/action-runtime-boundary.md +99 -0
  369. package/standard/adoption-levels.md +69 -0
  370. package/standard/conformance-levels.md +133 -0
  371. package/standard/context-pack-generation.md +141 -0
  372. package/standard/development-cockpit.md +67 -0
  373. package/standard/evidence-provenance.md +128 -0
  374. package/standard/feature-implementation-traceability.md +68 -0
  375. package/standard/federation-health.md +42 -0
  376. package/standard/feedback-learning-gate.md +101 -0
  377. package/standard/governance.md +137 -0
  378. package/standard/graph-as-ai-brain.md +81 -0
  379. package/standard/graph-dna-alignment.md +50 -0
  380. package/standard/graph-dna.md +70 -0
  381. package/standard/graph-embryo.md +69 -0
  382. package/standard/graph-seed.md +122 -0
  383. package/standard/hybrid-source-of-truth.md +91 -0
  384. package/standard/implementation-control-cycles.md +194 -0
  385. package/standard/implementation-control.md +102 -0
  386. package/standard/launch-record.md +53 -0
  387. package/standard/lifecycle-readiness.md +159 -0
  388. package/standard/multi-agent-coordination.md +50 -0
  389. package/standard/multi-source-quality-feedback.md +71 -0
  390. package/standard/object-model.md +152 -0
  391. package/standard/organization-governance.md +84 -0
  392. package/standard/process-control-contract.md +53 -0
  393. package/standard/profiles.md +233 -0
  394. package/standard/projection-views.md +69 -0
  395. package/standard/recovery-resume.md +49 -0
  396. package/standard/relation-model.md +139 -0
  397. package/standard/risk-control-matrix.md +53 -0
  398. package/standard/route-explanation.md +35 -0
  399. package/standard/route-regression.md +33 -0
  400. package/standard/routing-fixtures.md +54 -0
  401. package/standard/runtime-enablement.md +85 -0
  402. package/standard/source-boundary-contract.md +49 -0
  403. package/standard/standard-v0.1.md +132 -0
  404. package/standard/technology-quality-feedback.md +97 -0
  405. package/standard/test-suite.md +105 -0
  406. package/standard/work-state-machine.md +62 -0
  407. package/templates/README.md +64 -0
  408. package/templates/ai-employee-starter/README.md +9 -0
  409. package/templates/ai-employee-starter/gates/results.json +12 -0
  410. package/templates/ai-employee-starter/graph/objects.json +90 -0
  411. package/templates/ai-employee-starter/graph/relations.json +47 -0
  412. package/templates/ai-employee-starter/mirai-graph-package.json +14 -0
  413. package/templates/character-layer-starter/README.md +39 -0
  414. package/templates/character-layer-starter/gates/results.json +20 -0
  415. package/templates/character-layer-starter/graph/objects.json +308 -0
  416. package/templates/character-layer-starter/graph/relations.json +344 -0
  417. package/templates/character-layer-starter/mirai-graph-package.json +14 -0
  418. package/templates/organization-governance-starter/README.md +9 -0
  419. package/templates/organization-governance-starter/gates/results.json +12 -0
  420. package/templates/organization-governance-starter/graph/objects.json +112 -0
  421. package/templates/organization-governance-starter/graph/relations.json +65 -0
  422. package/templates/organization-governance-starter/mirai-graph-package.json +14 -0
  423. package/templates/research-program-starter/README.md +9 -0
  424. package/templates/research-program-starter/gates/results.json +12 -0
  425. package/templates/research-program-starter/graph/objects.json +79 -0
  426. package/templates/research-program-starter/graph/relations.json +47 -0
  427. package/templates/research-program-starter/mirai-graph-package.json +14 -0
  428. package/templates/software-project-starter/README.md +9 -0
  429. package/templates/software-project-starter/gates/results.json +12 -0
  430. package/templates/software-project-starter/graph/objects.json +79 -0
  431. package/templates/software-project-starter/graph/relations.json +47 -0
  432. package/templates/software-project-starter/mirai-graph-package.json +14 -0
@@ -0,0 +1,2434 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ const readinessValues = new Set([
7
+ "draft",
8
+ "review_ready",
9
+ "accepted",
10
+ "blocked",
11
+ "deprecated"
12
+ ]);
13
+
14
+ const coreObjectKinds = new Set([
15
+ "system",
16
+ "goal",
17
+ "requirement",
18
+ "feature",
19
+ "decision",
20
+ "risk",
21
+ "task",
22
+ "component",
23
+ "evidence",
24
+ "context_pack",
25
+ "governance_gate",
26
+ "profile"
27
+ ]);
28
+
29
+ const coreRelationTypes = new Set([
30
+ "depends_on",
31
+ "supports",
32
+ "blocks",
33
+ "implements",
34
+ "evidences",
35
+ "contradicts",
36
+ "governs",
37
+ "requires_approval_from",
38
+ "generates",
39
+ "derived_from",
40
+ "supersedes",
41
+ "belongs_to",
42
+ "related_to"
43
+ ]);
44
+
45
+ const conformanceLevels = new Set([
46
+ "level_0",
47
+ "level_1",
48
+ "level_2",
49
+ "level_3",
50
+ "level_4"
51
+ ]);
52
+
53
+ const gateVerdicts = new Set([
54
+ "pass",
55
+ "pass_with_notes",
56
+ "blocked",
57
+ "rejected",
58
+ "needs_more_evidence"
59
+ ]);
60
+
61
+ function usage() {
62
+ console.error("Usage:");
63
+ console.error(" node packages/cli/validate-mirai-graph.js <package-dir>");
64
+ console.error(" node packages/cli/validate-mirai-graph.js seed <seed-file>");
65
+ console.error(" node packages/cli/validate-mirai-graph.js profile <profile-file>");
66
+ console.error(" node packages/cli/validate-mirai-graph.js context-pack <package-dir> <context-pack-file>");
67
+ console.error(" node packages/cli/validate-mirai-graph.js implementation-control-cycle <cycle-result-file>");
68
+ console.error(" node packages/cli/validate-mirai-graph.js launch-record <launch-record-file>");
69
+ console.error(" node packages/cli/validate-mirai-graph.js process-transition <state-machine-file> <transition-request-file>");
70
+ console.error(" node packages/cli/validate-mirai-graph.js process-control-contract <contract-file>");
71
+ console.error(" node packages/cli/validate-mirai-graph.js technology-quality-feedback <feedback-file>");
72
+ console.error(" node packages/cli/validate-mirai-graph.js character-layer-integration <integration-file>");
73
+ console.error(" node packages/cli/validate-mirai-graph.js model-portability-evidence <evidence-file>");
74
+ console.error(" node packages/cli/validate-mirai-graph.js character-layer-readiness <readiness-file>");
75
+ console.error(" node packages/cli/validate-mirai-graph.js development-cockpit <cockpit-file>");
76
+ console.error(" node packages/cli/validate-mirai-graph.js feature-implementation-traceability <traceability-file>");
77
+ console.error(" node packages/cli/validate-mirai-graph.js multi-source-quality-feedback <feedback-file>");
78
+ console.error(" node packages/cli/validate-mirai-graph.js graph-dna-alignment <result-file>");
79
+ console.error(" node packages/cli/validate-mirai-graph.js work-state-machine <result-file>");
80
+ console.error(" node packages/cli/validate-mirai-graph.js recovery-resume-record <result-file>");
81
+ console.error(" node packages/cli/validate-mirai-graph.js risk-control-matrix <result-file>");
82
+ console.error(" node packages/cli/validate-mirai-graph.js multi-agent-coordination <result-file>");
83
+ console.error(" node packages/cli/validate-mirai-graph.js source-boundary-contract <result-file>");
84
+ console.error("");
85
+ console.error("Output options:");
86
+ console.error(" --json Print JSON output (default)");
87
+ console.error(" --markdown Print a human-readable Markdown report");
88
+ }
89
+
90
+ function markdownList(items, emptyText) {
91
+ if (!items || items.length === 0) {
92
+ return `- ${emptyText}`;
93
+ }
94
+ return items.map((item) => `- ${item}`).join("\n");
95
+ }
96
+
97
+ function formatInstrumentationMarkdown(output) {
98
+ const result = output.result || {};
99
+
100
+ if (output.mode === "development_cockpit") {
101
+ const instruments = Array.isArray(result.instruments)
102
+ ? result.instruments.map((instrument) => `\`${instrument.id}\`: ${instrument.family}, score \`${instrument.score}\`, band \`${instrument.band}\`, status \`${instrument.status}\``)
103
+ : [];
104
+ const nextAction = result.next_best_action || {};
105
+ return [
106
+ "# Development Cockpit Report",
107
+ "",
108
+ `- Valid: \`${output.valid ? "true" : "false"}\``,
109
+ `- Subject: \`${result.subject_ref || "unknown"}\``,
110
+ `- Generated at: \`${result.generated_at || "unknown"}\``,
111
+ `- Production readiness: \`${result.readiness ? result.readiness.production_readiness : "unknown"}\``,
112
+ `- Next action: \`${nextAction.action || "unknown"}\``,
113
+ `- Target cycle: \`${nextAction.target_cycle || "unknown"}\``,
114
+ "",
115
+ "## Instruments",
116
+ "",
117
+ markdownList(instruments, "No instruments declared."),
118
+ "",
119
+ "## Required Gates",
120
+ "",
121
+ markdownList(nextAction.required_gates || [], "No required gates declared."),
122
+ "",
123
+ "## Blocking Rules",
124
+ "",
125
+ markdownList(result.blocking_rules || [], "No blocking rules declared."),
126
+ "",
127
+ "## Errors",
128
+ "",
129
+ markdownList(output.errors, "No errors."),
130
+ "",
131
+ "## Warnings",
132
+ "",
133
+ markdownList(output.warnings, "No warnings."),
134
+ "",
135
+ "## Boundary",
136
+ "",
137
+ "- Cockpit metrics support steering, not acceptance or release.",
138
+ "- Evidence and proposals do not authorize canonical updates."
139
+ ].join("\n");
140
+ }
141
+
142
+ if (output.mode === "feature_implementation_traceability") {
143
+ const mappings = Array.isArray(result.implementation_mappings)
144
+ ? result.implementation_mappings.map((mapping) => `\`${mapping.feature_ref}\`: status \`${mapping.status}\`, confidence \`${mapping.confidence}\`, implementation refs \`${(mapping.implementation_refs || []).length}\`, evidence refs \`${(mapping.evidence_refs || []).length}\``)
145
+ : [];
146
+ const summary = result.coverage_summary || {};
147
+ return [
148
+ "# Feature Implementation Traceability Report",
149
+ "",
150
+ `- Valid: \`${output.valid ? "true" : "false"}\``,
151
+ `- Subject: \`${result.subject_ref || "unknown"}\``,
152
+ `- Features: \`${summary.feature_count !== undefined ? summary.feature_count : "unknown"}\``,
153
+ `- Mapped features: \`${summary.mapped_feature_count !== undefined ? summary.mapped_feature_count : "unknown"}\``,
154
+ `- Evidence-backed mappings: \`${summary.evidence_backed_mapping_count !== undefined ? summary.evidence_backed_mapping_count : "unknown"}\``,
155
+ `- Accepted features: \`${summary.accepted_feature_count !== undefined ? summary.accepted_feature_count : "unknown"}\``,
156
+ "",
157
+ "## Implementation Mappings",
158
+ "",
159
+ markdownList(mappings, "No implementation mappings declared."),
160
+ "",
161
+ "## Errors",
162
+ "",
163
+ markdownList(output.errors, "No errors."),
164
+ "",
165
+ "## Warnings",
166
+ "",
167
+ markdownList(output.warnings, "No warnings."),
168
+ "",
169
+ "## Boundary",
170
+ "",
171
+ "- Mapped intent is not implementation by itself.",
172
+ "- Accepted or released status requires the relevant evidence and gates."
173
+ ].join("\n");
174
+ }
175
+
176
+ if (output.mode === "multi_source_quality_feedback") {
177
+ const sources = Array.isArray(result.sources)
178
+ ? result.sources.map((source) => `\`${source.id}\`: ${source.kind}, verdict \`${source.verdict}\``)
179
+ : [];
180
+ const findings = Array.isArray(result.findings)
181
+ ? result.findings.map((finding) => `\`${finding.id}\`: ${finding.classification}, severity \`${finding.severity}\`, blocking \`${finding.blocking ? "true" : "false"}\`, route \`${finding.next_route}\``)
182
+ : [];
183
+ return [
184
+ "# Multi-Source Quality Feedback Report",
185
+ "",
186
+ `- Valid: \`${output.valid ? "true" : "false"}\``,
187
+ `- Process: \`${result.process_id || "unknown"}\``,
188
+ `- Verdict: \`${result.verdict || "unknown"}\``,
189
+ `- Next transition: \`${result.next_transition || "unknown"}\``,
190
+ `- Blocking findings: \`${Array.isArray(result.blocking_findings) ? result.blocking_findings.length : "unknown"}\``,
191
+ "",
192
+ "## Sources",
193
+ "",
194
+ markdownList(sources, "No sources declared."),
195
+ "",
196
+ "## Findings",
197
+ "",
198
+ markdownList(findings, "No findings declared."),
199
+ "",
200
+ "## Kaizen Refs",
201
+ "",
202
+ markdownList(result.kaizen_refs || [], "No Kaizen refs declared."),
203
+ "",
204
+ "## Errors",
205
+ "",
206
+ markdownList(output.errors, "No errors."),
207
+ "",
208
+ "## Warnings",
209
+ "",
210
+ markdownList(output.warnings, "No warnings."),
211
+ "",
212
+ "## Boundary",
213
+ "",
214
+ "- Multi-source feedback calibrates transitions; it is not approval by itself.",
215
+ "- Blocking findings stop the transitions they block."
216
+ ].join("\n");
217
+ }
218
+
219
+ return null;
220
+ }
221
+
222
+ function formatMarkdownReport(output) {
223
+ const instrumentationReport = formatInstrumentationMarkdown(output);
224
+ if (instrumentationReport) {
225
+ return instrumentationReport;
226
+ }
227
+
228
+ if (output.mode === "process_transition" && output.explanation) {
229
+ const explanation = output.explanation;
230
+ const gate = explanation.kaizen_decision || {};
231
+ return [
232
+ "# Process Transition Decision Report",
233
+ "",
234
+ `- Valid: \`${output.valid ? "true" : "false"}\``,
235
+ `- Process: \`${explanation.process_id || "unknown"}\``,
236
+ `- Transition: \`${explanation.current_state || "unknown"} -> ${explanation.target_state || "unknown"}\``,
237
+ `- Matched transition: \`${explanation.matched_transition ? "true" : "false"}\``,
238
+ `- Requires launch record: \`${explanation.requires_launch_record ? "true" : "false"}\``,
239
+ `- Launch record satisfied: \`${explanation.launch_record_satisfied ? "true" : "false"}\``,
240
+ `- Terminal transition: \`${explanation.terminal_transition ? "true" : "false"}\``,
241
+ `- Kaizen decision: \`${gate.status || "not_required"}\``,
242
+ "",
243
+ "## Required Evidence",
244
+ "",
245
+ markdownList(explanation.required_evidence, "No evidence required by matched transition."),
246
+ "",
247
+ "## Provided Evidence",
248
+ "",
249
+ markdownList(explanation.provided_evidence, "No evidence provided."),
250
+ "",
251
+ "## Missing Evidence",
252
+ "",
253
+ markdownList(explanation.missing_evidence, "No missing evidence."),
254
+ "",
255
+ "## False-Transition Guards",
256
+ "",
257
+ markdownList(explanation.false_transition_guard_summary, "No false-transition guards declared."),
258
+ "",
259
+ "## Errors",
260
+ "",
261
+ markdownList(output.errors, "No errors."),
262
+ "",
263
+ "## Warnings",
264
+ "",
265
+ markdownList(output.warnings, "No warnings."),
266
+ "",
267
+ "## Boundary",
268
+ "",
269
+ "- A passing transition report validates this requested transition only.",
270
+ "- Readiness, evidence and proposals do not authorize canonical updates."
271
+ ].join("\n");
272
+ }
273
+
274
+ const lines = [
275
+ "# Mirai Graph Validation Report",
276
+ "",
277
+ `- Mode: \`${output.mode}\``,
278
+ `- Valid: \`${output.valid ? "true" : "false"}\``,
279
+ `- Target: \`${output.target}\``
280
+ ];
281
+
282
+ if (output.package) {
283
+ lines.push(`- Package: \`${output.package}\``);
284
+ }
285
+ if (output.state_machine) {
286
+ lines.push(`- State machine: \`${output.state_machine}\``);
287
+ }
288
+
289
+ lines.push(
290
+ "",
291
+ "## Errors",
292
+ "",
293
+ markdownList(output.errors, "No errors."),
294
+ "",
295
+ "## Warnings",
296
+ "",
297
+ markdownList(output.warnings, "No warnings."),
298
+ "",
299
+ "## Boundary",
300
+ "",
301
+ "- A passing validation report is evidence for this check only.",
302
+ "- Generated context, evidence and proposals do not authorize canonical updates."
303
+ );
304
+
305
+ return lines.join("\n");
306
+ }
307
+
308
+ function readJson(filePath) {
309
+ try {
310
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
311
+ } catch (error) {
312
+ throw new Error(`Cannot read JSON ${filePath}: ${error.message}`);
313
+ }
314
+ }
315
+
316
+ function findManifestPath(packageDir) {
317
+ return path.join(packageDir, "mirai-graph-package.json");
318
+ }
319
+
320
+ function asArray(value, label, errors) {
321
+ if (!Array.isArray(value)) {
322
+ errors.push(`${label} must be an array`);
323
+ return [];
324
+ }
325
+ return value;
326
+ }
327
+
328
+ function requireString(item, field, label, errors) {
329
+ if (typeof item[field] !== "string" || item[field].trim() === "") {
330
+ errors.push(`${label}.${field} must be a non-empty string`);
331
+ }
332
+ }
333
+
334
+ function requireArray(item, field, label, errors) {
335
+ if (!Array.isArray(item[field])) {
336
+ errors.push(`${label}.${field} must be an array`);
337
+ return;
338
+ }
339
+ const seen = new Set();
340
+ for (const value of item[field]) {
341
+ if (typeof value !== "string" || value.trim() === "") {
342
+ errors.push(`${label}.${field} must contain only non-empty strings`);
343
+ continue;
344
+ }
345
+ if (seen.has(value)) {
346
+ errors.push(`${label}.${field} contains duplicate value ${value}`);
347
+ }
348
+ seen.add(value);
349
+ }
350
+ }
351
+
352
+ function requireJsonArray(item, field, label, errors) {
353
+ if (!Array.isArray(item[field])) {
354
+ errors.push(`${label}.${field} must be an array`);
355
+ }
356
+ }
357
+
358
+ function requireOptionalArray(item, field, label, errors) {
359
+ if (item[field] === undefined) {
360
+ return;
361
+ }
362
+ requireArray(item, field, label, errors);
363
+ }
364
+
365
+ function isValidDateTime(value) {
366
+ return typeof value === "string" && value.trim() !== "" && !Number.isNaN(Date.parse(value));
367
+ }
368
+
369
+ function canonicalRelationId(relation) {
370
+ if (
371
+ typeof relation.source !== "string" ||
372
+ typeof relation.type !== "string" ||
373
+ typeof relation.target !== "string"
374
+ ) {
375
+ return null;
376
+ }
377
+ return `relation.${relation.source}.${relation.type}.${relation.target}`;
378
+ }
379
+
380
+ function profileSlug(profileName) {
381
+ return profileName.replace(/_/g, "-");
382
+ }
383
+
384
+ function loadProfile(profileName) {
385
+ if (profileName === "core") {
386
+ return {
387
+ allowed_object_kinds: Array.from(coreObjectKinds),
388
+ allowed_relation_types: Array.from(coreRelationTypes)
389
+ };
390
+ }
391
+
392
+ const profilePath = path.resolve(__dirname, "..", "..", "profiles", profileSlug(profileName), "profile.json");
393
+ if (!fs.existsSync(profilePath)) {
394
+ return null;
395
+ }
396
+
397
+ return readJson(profilePath);
398
+ }
399
+
400
+ function includesAnyLowercase(text, terms) {
401
+ if (typeof text !== "string") {
402
+ return null;
403
+ }
404
+ const lower = text.toLowerCase();
405
+ return terms.find((term) => lower.includes(term));
406
+ }
407
+
408
+ function validateCharacterLayerSemantics(objects, relations, errors) {
409
+ const objectById = new Map(objects.map((object) => [object.id, object]));
410
+ const kindOf = (id) => objectById.get(id) && objectById.get(id).kind;
411
+ const hasKind = (id, kinds) => kinds.includes(kindOf(id));
412
+
413
+ const relationShapes = {
414
+ defines_principle: {
415
+ source: ["character_constitution"],
416
+ target: ["character_principle"]
417
+ },
418
+ promotes_virtue: {
419
+ source: ["character_constitution"],
420
+ target: ["character_virtue"]
421
+ },
422
+ sets_character_boundary: {
423
+ source: ["character_constitution"],
424
+ target: ["character_boundary"]
425
+ },
426
+ specializes_character: {
427
+ source: ["role_character_profile"],
428
+ target: ["character_constitution"]
429
+ },
430
+ uses_reflection_protocol: {
431
+ source: ["role_character_profile", "correction_loop"],
432
+ target: ["reflection_protocol"]
433
+ },
434
+ tests_character: {
435
+ source: ["character_fixture"],
436
+ target: ["role_character_profile", "character_constitution"]
437
+ },
438
+ describes_violation_of: {
439
+ source: ["violation_pattern"],
440
+ target: ["character_principle", "character_boundary", "character_virtue", "character_decision_rule"]
441
+ },
442
+ corrects_violation: {
443
+ source: ["correction_loop"],
444
+ target: ["violation_pattern"]
445
+ },
446
+ updates_character: {
447
+ source: ["correction_loop"],
448
+ target: ["role_character_profile", "character_constitution", "character_principle", "character_boundary", "character_decision_rule", "reflection_protocol"]
449
+ },
450
+ evidences_character: {
451
+ source: ["evidence"],
452
+ target: ["character_constitution", "character_principle", "character_virtue", "character_boundary", "role_character_profile", "character_decision_rule", "reflection_protocol", "character_fixture", "violation_pattern", "correction_loop"]
453
+ },
454
+ requires_escalation_to: {
455
+ source: ["character_boundary", "violation_pattern"],
456
+ target: ["governance_gate"]
457
+ },
458
+ governs: {
459
+ source: ["governance_gate"],
460
+ target: ["role_character_profile", "character_constitution", "character_boundary", "correction_loop"]
461
+ }
462
+ };
463
+
464
+ for (const [index, relation] of relations.entries()) {
465
+ const label = `relation[${index}]`;
466
+ const shape = relationShapes[relation.type];
467
+ if (!shape || !objectById.has(relation.source) || !objectById.has(relation.target)) {
468
+ continue;
469
+ }
470
+ if (!hasKind(relation.source, shape.source)) {
471
+ errors.push(`${label}.source kind ${kindOf(relation.source)} is invalid for character_layer relation ${relation.type}; expected ${shape.source.join(" or ")}`);
472
+ }
473
+ if (!hasKind(relation.target, shape.target)) {
474
+ errors.push(`${label}.target kind ${kindOf(relation.target)} is invalid for character_layer relation ${relation.type}; expected ${shape.target.join(" or ")}`);
475
+ }
476
+ }
477
+
478
+ const forbiddenAuthorityTerms = [
479
+ "generated context authorizes",
480
+ "evidence authorizes",
481
+ "proposal authorizes",
482
+ "authorizes external action",
483
+ "authorizes canonical update",
484
+ "authorization is granted by evidence"
485
+ ];
486
+ const forbiddenAutomaticUpdateTerms = [
487
+ "feedback automatically updates",
488
+ "automatically updates canonical",
489
+ "automatic canonical update",
490
+ "auto canonical update",
491
+ "canonical state changes automatically"
492
+ ];
493
+ const forbiddenRolePermissionTerms = [
494
+ "grants tool permission",
495
+ "grants runtime permission",
496
+ "grants external action permission",
497
+ "can execute tools without approval",
498
+ "can bypass approval"
499
+ ];
500
+
501
+ for (const [index, object] of objects.entries()) {
502
+ const label = `object[${index}]`;
503
+ const haystack = `${object.title || ""}\n${object.summary || ""}`;
504
+ const authorityTerm = includesAnyLowercase(haystack, forbiddenAuthorityTerms);
505
+ if (authorityTerm) {
506
+ errors.push(`${label} contains forbidden character_layer authorization semantics: ${authorityTerm}`);
507
+ }
508
+ const automaticUpdateTerm = includesAnyLowercase(haystack, forbiddenAutomaticUpdateTerms);
509
+ if (automaticUpdateTerm) {
510
+ errors.push(`${label} contains forbidden character_layer automatic-update semantics: ${automaticUpdateTerm}`);
511
+ }
512
+ if (object.kind === "role_character_profile") {
513
+ const permissionTerm = includesAnyLowercase(haystack, forbiddenRolePermissionTerms);
514
+ if (permissionTerm) {
515
+ errors.push(`${label} contains forbidden role_character_profile runtime-permission semantics: ${permissionTerm}`);
516
+ }
517
+ }
518
+ if (object.kind === "correction_loop") {
519
+ const ownerReviewText = haystack.toLowerCase();
520
+ if (!ownerReviewText.includes("owner review") && !ownerReviewText.includes("human review")) {
521
+ errors.push(`${label} correction_loop must mention owner review or human review before canonical character updates`);
522
+ }
523
+ }
524
+ }
525
+ }
526
+
527
+ function validatePackage(packageDir) {
528
+ const manifestLookup = findManifestPath(packageDir);
529
+ const manifest = fs.existsSync(manifestLookup) ? readJson(manifestLookup) : null;
530
+ const graphDir = path.join(packageDir, "graph");
531
+ const objectsPath = manifest
532
+ ? path.join(packageDir, manifest.graph && manifest.graph.objects ? manifest.graph.objects : "")
533
+ : path.join(graphDir, "objects.json");
534
+ const relationsPath = manifest
535
+ ? path.join(packageDir, manifest.graph && manifest.graph.relations ? manifest.graph.relations : "")
536
+ : path.join(graphDir, "relations.json");
537
+ const gateResultsPath = path.join(packageDir, "gates", "results.json");
538
+ const errors = [];
539
+ const warnings = [];
540
+
541
+ if (manifest) {
542
+ requireString(manifest, "id", "manifest", errors);
543
+ requireString(manifest, "name", "manifest", errors);
544
+ requireString(manifest, "version", "manifest", errors);
545
+ requireString(manifest, "profile", "manifest", errors);
546
+ requireString(manifest, "conformance_level", "manifest", errors);
547
+
548
+ if (!manifest.graph || typeof manifest.graph !== "object") {
549
+ errors.push("manifest.graph must be an object");
550
+ } else {
551
+ requireString(manifest.graph, "objects", "manifest.graph", errors);
552
+ requireString(manifest.graph, "relations", "manifest.graph", errors);
553
+ }
554
+
555
+ if (
556
+ typeof manifest.conformance_level === "string" &&
557
+ !conformanceLevels.has(manifest.conformance_level)
558
+ ) {
559
+ errors.push(`manifest.conformance_level has unsupported value ${manifest.conformance_level}`);
560
+ }
561
+ } else {
562
+ warnings.push("Missing mirai-graph-package.json manifest");
563
+ }
564
+
565
+ if (!fs.existsSync(objectsPath)) {
566
+ errors.push(`Missing ${objectsPath}`);
567
+ }
568
+ if (!fs.existsSync(relationsPath)) {
569
+ errors.push(`Missing ${relationsPath}`);
570
+ }
571
+ if (errors.length > 0) {
572
+ return { errors, warnings };
573
+ }
574
+
575
+ const objects = asArray(readJson(objectsPath), "graph/objects.json", errors);
576
+ const relations = asArray(readJson(relationsPath), "graph/relations.json", errors);
577
+ const packageProfile = manifest && typeof manifest.profile === "string" ? loadProfile(manifest.profile) : null;
578
+ const allowedObjectKinds = packageProfile ? new Set(packageProfile.allowed_object_kinds || []) : null;
579
+ const allowedRelationTypes = packageProfile ? new Set(packageProfile.allowed_relation_types || []) : null;
580
+
581
+ if (manifest && typeof manifest.profile === "string" && !packageProfile) {
582
+ warnings.push(`No local profile definition found for manifest.profile ${manifest.profile}`);
583
+ }
584
+
585
+ const objectIds = new Set();
586
+
587
+ for (const [index, object] of objects.entries()) {
588
+ const label = `object[${index}]`;
589
+ requireString(object, "id", label, errors);
590
+ requireString(object, "kind", label, errors);
591
+ requireString(object, "title", label, errors);
592
+ requireString(object, "summary", label, errors);
593
+ requireString(object, "readiness", label, errors);
594
+ requireString(object, "profile", label, errors);
595
+ requireArray(object, "evidence", label, errors);
596
+
597
+ if (typeof object.id === "string") {
598
+ if (objectIds.has(object.id)) {
599
+ errors.push(`${label}.id duplicates ${object.id}`);
600
+ }
601
+ objectIds.add(object.id);
602
+ }
603
+
604
+ if (typeof object.readiness === "string" && !readinessValues.has(object.readiness)) {
605
+ errors.push(`${label}.readiness has unsupported value ${object.readiness}`);
606
+ }
607
+
608
+ if (typeof object.kind === "string" && object.profile === "core" && !coreObjectKinds.has(object.kind)) {
609
+ warnings.push(`${label}.kind ${object.kind} is not a core object kind`);
610
+ }
611
+
612
+ if (typeof object.kind === "string" && allowedObjectKinds && !allowedObjectKinds.has(object.kind)) {
613
+ errors.push(`${label}.kind ${object.kind} is not allowed by manifest.profile ${manifest.profile}`);
614
+ }
615
+ }
616
+
617
+ const evidenceIds = new Set(
618
+ objects
619
+ .filter((object) => object.kind === "evidence")
620
+ .map((object) => object.id)
621
+ );
622
+ const relationIds = new Set();
623
+
624
+ for (const [index, relation] of relations.entries()) {
625
+ const label = `relation[${index}]`;
626
+ requireString(relation, "id", label, errors);
627
+ requireString(relation, "type", label, errors);
628
+ requireString(relation, "source", label, errors);
629
+ requireString(relation, "target", label, errors);
630
+ requireString(relation, "readiness", label, errors);
631
+ requireString(relation, "profile", label, errors);
632
+ requireArray(relation, "evidence", label, errors);
633
+
634
+ if (typeof relation.id === "string") {
635
+ if (relationIds.has(relation.id)) {
636
+ errors.push(`${label}.id duplicates ${relation.id}`);
637
+ }
638
+ relationIds.add(relation.id);
639
+
640
+ const expectedRelationId = canonicalRelationId(relation);
641
+ if (expectedRelationId && relation.id !== expectedRelationId) {
642
+ errors.push(`${label}.id must be ${expectedRelationId} for its source/type/target`);
643
+ }
644
+ }
645
+
646
+ if (typeof relation.source === "string" && !objectIds.has(relation.source)) {
647
+ errors.push(`${label}.source references missing object ${relation.source}`);
648
+ }
649
+
650
+ if (typeof relation.target === "string" && !objectIds.has(relation.target)) {
651
+ errors.push(`${label}.target references missing object ${relation.target}`);
652
+ }
653
+
654
+ if (typeof relation.readiness === "string" && !readinessValues.has(relation.readiness)) {
655
+ errors.push(`${label}.readiness has unsupported value ${relation.readiness}`);
656
+ }
657
+
658
+ if (typeof relation.type === "string" && relation.profile === "core" && !coreRelationTypes.has(relation.type)) {
659
+ warnings.push(`${label}.type ${relation.type} is not a core relation type`);
660
+ }
661
+
662
+ if (typeof relation.type === "string" && allowedRelationTypes && !allowedRelationTypes.has(relation.type)) {
663
+ errors.push(`${label}.type ${relation.type} is not allowed by manifest.profile ${manifest.profile}`);
664
+ }
665
+
666
+ if (Array.isArray(relation.evidence)) {
667
+ for (const evidenceRef of relation.evidence) {
668
+ if (!evidenceIds.has(evidenceRef) && !objectIds.has(evidenceRef)) {
669
+ warnings.push(`${label}.evidence references non-object evidence ${evidenceRef}`);
670
+ }
671
+ }
672
+ }
673
+ }
674
+
675
+ if (manifest && manifest.profile === "character_layer") {
676
+ validateCharacterLayerSemantics(objects, relations, errors);
677
+ }
678
+
679
+ if (fs.existsSync(gateResultsPath)) {
680
+ const gateResults = asArray(readJson(gateResultsPath), "gates/results.json", errors);
681
+ const gateResultIds = new Set();
682
+
683
+ for (const [index, gateResult] of gateResults.entries()) {
684
+ const label = `gate_result[${index}]`;
685
+ requireString(gateResult, "id", label, errors);
686
+ requireString(gateResult, "gate_id", label, errors);
687
+ requireString(gateResult, "target_id", label, errors);
688
+ requireString(gateResult, "verdict", label, errors);
689
+ requireString(gateResult, "summary", label, errors);
690
+ requireString(gateResult, "reviewed_at", label, errors);
691
+ requireArray(gateResult, "evidence", label, errors);
692
+
693
+ if (typeof gateResult.id === "string") {
694
+ if (gateResultIds.has(gateResult.id)) {
695
+ errors.push(`${label}.id duplicates ${gateResult.id}`);
696
+ }
697
+ gateResultIds.add(gateResult.id);
698
+ }
699
+
700
+ if (typeof gateResult.verdict === "string" && !gateVerdicts.has(gateResult.verdict)) {
701
+ errors.push(`${label}.verdict has unsupported value ${gateResult.verdict}`);
702
+ }
703
+
704
+ if (
705
+ typeof gateResult.target_id === "string" &&
706
+ manifest &&
707
+ gateResult.target_id !== manifest.id &&
708
+ !objectIds.has(gateResult.target_id) &&
709
+ !relationIds.has(gateResult.target_id)
710
+ ) {
711
+ warnings.push(`${label}.target_id references non-graph target ${gateResult.target_id}`);
712
+ }
713
+ }
714
+ }
715
+
716
+ return { errors, warnings };
717
+ }
718
+
719
+ function requireObject(item, field, label, errors) {
720
+ if (!item[field] || typeof item[field] !== "object" || Array.isArray(item[field])) {
721
+ errors.push(`${label}.${field} must be an object`);
722
+ }
723
+ }
724
+
725
+ function validateSeed(seedPath) {
726
+ const errors = [];
727
+ const warnings = [];
728
+ const seed = readJson(seedPath);
729
+ const label = "seed";
730
+
731
+ requireString(seed, "schema_version", label, errors);
732
+ requireString(seed, "seed_id", label, errors);
733
+ requireString(seed, "target_graph_id", label, errors);
734
+ requireString(seed, "purpose", label, errors);
735
+ requireString(seed, "target_profile", label, errors);
736
+ requireString(seed, "target_mode", label, errors);
737
+ requireObject(seed, "graph_dna", label, errors);
738
+ requireObject(seed, "source_boundaries", label, errors);
739
+ requireObject(seed, "growth_rules", label, errors);
740
+ requireArray(seed, "review_gates", label, errors);
741
+ requireArray(seed, "generated_views", label, errors);
742
+ requireArray(seed, "stop_conditions", label, errors);
743
+
744
+ const targetModes = new Set([
745
+ "discovery",
746
+ "canonical",
747
+ "pilot",
748
+ "controlled_runtime",
749
+ "production_runtime"
750
+ ]);
751
+
752
+ if (typeof seed.target_mode === "string" && !targetModes.has(seed.target_mode)) {
753
+ errors.push(`${label}.target_mode has unsupported value ${seed.target_mode}`);
754
+ }
755
+
756
+ if (seed.graph_dna && typeof seed.graph_dna === "object") {
757
+ requireString(seed.graph_dna, "purpose", "seed.graph_dna", errors);
758
+ requireString(seed.graph_dna, "evolution_vector", "seed.graph_dna", errors);
759
+ requireArray(seed.graph_dna, "non_negotiable_principles", "seed.graph_dna", errors);
760
+ }
761
+
762
+ if (seed.source_boundaries && typeof seed.source_boundaries === "object") {
763
+ requireArray(seed.source_boundaries, "allowed_sources", "seed.source_boundaries", errors);
764
+ requireArray(seed.source_boundaries, "excluded_sources", "seed.source_boundaries", errors);
765
+ if (typeof seed.source_boundaries.canonical_write_allowed !== "boolean") {
766
+ errors.push("seed.source_boundaries.canonical_write_allowed must be a boolean");
767
+ }
768
+ }
769
+
770
+ if (seed.growth_rules && typeof seed.growth_rules === "object") {
771
+ requireArray(seed.growth_rules, "allowed_object_families", "seed.growth_rules", errors);
772
+ requireArray(seed.growth_rules, "allowed_relation_families", "seed.growth_rules", errors);
773
+ if (!Number.isInteger(seed.growth_rules.max_initial_objects) || seed.growth_rules.max_initial_objects < 1) {
774
+ errors.push("seed.growth_rules.max_initial_objects must be a positive integer");
775
+ }
776
+ if (!["light", "standard", "broad"].includes(seed.growth_rules.depth_mode)) {
777
+ errors.push("seed.growth_rules.depth_mode must be light, standard or broad");
778
+ }
779
+ }
780
+
781
+ if (
782
+ seed.source_boundaries &&
783
+ seed.source_boundaries.canonical_write_allowed === true &&
784
+ Array.isArray(seed.review_gates) &&
785
+ !seed.review_gates.includes("human_review_before_canonical_write")
786
+ ) {
787
+ warnings.push("canonical_write_allowed is true without human_review_before_canonical_write gate");
788
+ }
789
+
790
+ return { errors, warnings };
791
+ }
792
+
793
+ function validateProfile(profilePath) {
794
+ const errors = [];
795
+ const warnings = [];
796
+ const profile = readJson(profilePath);
797
+ const label = "profile";
798
+
799
+ requireString(profile, "id", label, errors);
800
+ requireString(profile, "name", label, errors);
801
+ requireString(profile, "version", label, errors);
802
+ requireString(profile, "description", label, errors);
803
+ requireArray(profile, "allowed_object_kinds", label, errors);
804
+ requireArray(profile, "allowed_relation_types", label, errors);
805
+ requireString(profile, "default_readiness", label, errors);
806
+ requireArray(profile, "governance_gates", label, errors);
807
+
808
+ if (typeof profile.default_readiness === "string" && !readinessValues.has(profile.default_readiness)) {
809
+ errors.push(`${label}.default_readiness has unsupported value ${profile.default_readiness}`);
810
+ }
811
+
812
+ if (Array.isArray(profile.allowed_object_kinds) && profile.allowed_object_kinds.length === 0) {
813
+ warnings.push("profile.allowed_object_kinds is empty");
814
+ }
815
+
816
+ if (Array.isArray(profile.allowed_relation_types) && profile.allowed_relation_types.length === 0) {
817
+ warnings.push("profile.allowed_relation_types is empty");
818
+ }
819
+
820
+ return { errors, warnings };
821
+ }
822
+
823
+ function loadPackageGraph(packageDir, errors) {
824
+ const manifestLookup = findManifestPath(packageDir);
825
+ const manifest = fs.existsSync(manifestLookup) ? readJson(manifestLookup) : null;
826
+ const graphDir = path.join(packageDir, "graph");
827
+ const objectsPath = manifest
828
+ ? path.join(packageDir, manifest.graph && manifest.graph.objects ? manifest.graph.objects : "")
829
+ : path.join(graphDir, "objects.json");
830
+ const relationsPath = manifest
831
+ ? path.join(packageDir, manifest.graph && manifest.graph.relations ? manifest.graph.relations : "")
832
+ : path.join(graphDir, "relations.json");
833
+
834
+ if (!fs.existsSync(objectsPath)) {
835
+ errors.push(`Missing ${objectsPath}`);
836
+ }
837
+ if (!fs.existsSync(relationsPath)) {
838
+ errors.push(`Missing ${relationsPath}`);
839
+ }
840
+ if (errors.length > 0) {
841
+ return { manifest, objects: [], relations: [] };
842
+ }
843
+
844
+ return {
845
+ manifest,
846
+ objects: asArray(readJson(objectsPath), "graph/objects.json", errors),
847
+ relations: asArray(readJson(relationsPath), "graph/relations.json", errors)
848
+ };
849
+ }
850
+
851
+ function validateStringSet(values, knownIds, label, errors) {
852
+ const seen = new Set();
853
+ for (const value of values) {
854
+ if (seen.has(value)) {
855
+ errors.push(`${label} contains duplicate value ${value}`);
856
+ }
857
+ seen.add(value);
858
+ if (!knownIds.has(value)) {
859
+ errors.push(`${label} references unknown id ${value}`);
860
+ }
861
+ }
862
+ }
863
+
864
+ function validateContextPack(packageDir, contextPackPath) {
865
+ const errors = [];
866
+ const warnings = [];
867
+ const { manifest, objects, relations } = loadPackageGraph(packageDir, errors);
868
+ if (errors.length > 0) {
869
+ return { errors, warnings };
870
+ }
871
+
872
+ const contextPack = readJson(contextPackPath);
873
+ const label = "context_pack";
874
+ requireString(contextPack, "id", label, errors);
875
+ requireString(contextPack, "task_id", label, errors);
876
+ requireString(contextPack, "source_graph", label, errors);
877
+ requireString(contextPack, "generated_at", label, errors);
878
+ requireArray(contextPack, "included_objects", label, errors);
879
+ requireArray(contextPack, "included_relations", label, errors);
880
+ requireArray(contextPack, "evidence", label, errors);
881
+ requireArray(contextPack, "limitations", label, errors);
882
+ requireOptionalArray(contextPack, "assumptions", label, errors);
883
+ requireOptionalArray(contextPack, "omissions", label, errors);
884
+
885
+ if (typeof contextPack.id === "string" && !contextPack.id.startsWith("context_pack.")) {
886
+ warnings.push("context_pack.id should start with context_pack.");
887
+ }
888
+
889
+ if (contextPack.generated_at !== undefined && !isValidDateTime(contextPack.generated_at)) {
890
+ errors.push("context_pack.generated_at must be a parseable date-time string");
891
+ }
892
+
893
+ if (manifest && contextPack.source_graph !== manifest.id) {
894
+ errors.push(`context_pack.source_graph must match manifest.id ${manifest.id}`);
895
+ }
896
+
897
+ if (Array.isArray(contextPack.limitations) && contextPack.limitations.length === 0) {
898
+ warnings.push("context_pack.limitations is empty");
899
+ }
900
+
901
+ const objectIds = new Set(objects.map((object) => object.id));
902
+ const relationIds = new Set(relations.map((relation) => relation.id));
903
+ const evidenceObjectIds = new Set(
904
+ objects
905
+ .filter((object) => object.kind === "evidence")
906
+ .map((object) => object.id)
907
+ );
908
+
909
+ if (Array.isArray(contextPack.included_objects)) {
910
+ validateStringSet(contextPack.included_objects, objectIds, "context_pack.included_objects", errors);
911
+ }
912
+ if (Array.isArray(contextPack.included_relations)) {
913
+ validateStringSet(contextPack.included_relations, relationIds, "context_pack.included_relations", errors);
914
+ }
915
+ if (Array.isArray(contextPack.evidence)) {
916
+ validateStringSet(contextPack.evidence, objectIds, "context_pack.evidence", errors);
917
+ for (const evidenceId of contextPack.evidence) {
918
+ if (objectIds.has(evidenceId) && !evidenceObjectIds.has(evidenceId)) {
919
+ warnings.push(`context_pack.evidence includes non-evidence object ${evidenceId}`);
920
+ }
921
+ }
922
+ }
923
+
924
+ const selectedObjectIds = new Set(Array.isArray(contextPack.included_objects) ? contextPack.included_objects : []);
925
+ for (const relation of relations) {
926
+ if (!Array.isArray(contextPack.included_relations) || !contextPack.included_relations.includes(relation.id)) {
927
+ continue;
928
+ }
929
+ if (!selectedObjectIds.has(relation.source)) {
930
+ errors.push(`included relation ${relation.id} has source outside included_objects: ${relation.source}`);
931
+ }
932
+ if (!selectedObjectIds.has(relation.target)) {
933
+ errors.push(`included relation ${relation.id} has target outside included_objects: ${relation.target}`);
934
+ }
935
+ }
936
+
937
+ if (!contextPack.selection) {
938
+ warnings.push("context_pack.selection is missing; generated packs should explain selection metadata");
939
+ return { errors, warnings };
940
+ }
941
+
942
+ if (typeof contextPack.selection !== "object" || Array.isArray(contextPack.selection)) {
943
+ errors.push("context_pack.selection must be an object");
944
+ return { errors, warnings };
945
+ }
946
+
947
+ requireString(contextPack.selection, "method", "context_pack.selection", errors);
948
+ requireArray(contextPack.selection, "task_tokens", "context_pack.selection", errors);
949
+ requireJsonArray(contextPack.selection, "object_explanations", "context_pack.selection", errors);
950
+ requireJsonArray(contextPack.selection, "relation_explanations", "context_pack.selection", errors);
951
+
952
+ if (Array.isArray(contextPack.selection.task_tokens) && contextPack.selection.task_tokens.length === 0) {
953
+ warnings.push("context_pack.selection.task_tokens is empty");
954
+ }
955
+
956
+ const explainedObjectIds = new Set();
957
+ if (Array.isArray(contextPack.selection.object_explanations)) {
958
+ for (const [index, explanation] of contextPack.selection.object_explanations.entries()) {
959
+ const explanationLabel = `context_pack.selection.object_explanations[${index}]`;
960
+ requireString(explanation, "id", explanationLabel, errors);
961
+ requireArray(explanation, "reasons", explanationLabel, errors);
962
+
963
+ if (typeof explanation.relevance_score !== "number" || !Number.isFinite(explanation.relevance_score)) {
964
+ errors.push(`${explanationLabel}.relevance_score must be a finite number`);
965
+ }
966
+ if (typeof explanation.id === "string") {
967
+ if (explainedObjectIds.has(explanation.id)) {
968
+ errors.push(`${explanationLabel}.id duplicates ${explanation.id}`);
969
+ }
970
+ explainedObjectIds.add(explanation.id);
971
+ if (!selectedObjectIds.has(explanation.id)) {
972
+ errors.push(`${explanationLabel}.id must reference included object ${explanation.id}`);
973
+ }
974
+ }
975
+ if (Array.isArray(explanation.reasons) && explanation.reasons.length === 0) {
976
+ warnings.push(`${explanationLabel}.reasons is empty`);
977
+ }
978
+ }
979
+ }
980
+
981
+ for (const objectId of selectedObjectIds) {
982
+ if (!explainedObjectIds.has(objectId)) {
983
+ errors.push(`included object ${objectId} is missing selection.object_explanations entry`);
984
+ }
985
+ }
986
+
987
+ const selectedRelationIds = new Set(Array.isArray(contextPack.included_relations) ? contextPack.included_relations : []);
988
+ const explainedRelationIds = new Set();
989
+ if (Array.isArray(contextPack.selection.relation_explanations)) {
990
+ for (const [index, explanation] of contextPack.selection.relation_explanations.entries()) {
991
+ const explanationLabel = `context_pack.selection.relation_explanations[${index}]`;
992
+ requireString(explanation, "id", explanationLabel, errors);
993
+ requireString(explanation, "reason", explanationLabel, errors);
994
+ requireString(explanation, "source", explanationLabel, errors);
995
+ requireString(explanation, "target", explanationLabel, errors);
996
+ if (typeof explanation.id === "string") {
997
+ if (explainedRelationIds.has(explanation.id)) {
998
+ errors.push(`${explanationLabel}.id duplicates ${explanation.id}`);
999
+ }
1000
+ explainedRelationIds.add(explanation.id);
1001
+ if (!selectedRelationIds.has(explanation.id)) {
1002
+ errors.push(`${explanationLabel}.id must reference included relation ${explanation.id}`);
1003
+ }
1004
+ }
1005
+ if (typeof explanation.source === "string" && !selectedObjectIds.has(explanation.source)) {
1006
+ errors.push(`${explanationLabel}.source must reference an included object`);
1007
+ }
1008
+ if (typeof explanation.target === "string" && !selectedObjectIds.has(explanation.target)) {
1009
+ errors.push(`${explanationLabel}.target must reference an included object`);
1010
+ }
1011
+ }
1012
+ }
1013
+
1014
+ for (const relationId of selectedRelationIds) {
1015
+ if (!explainedRelationIds.has(relationId)) {
1016
+ errors.push(`included relation ${relationId} is missing selection.relation_explanations entry`);
1017
+ }
1018
+ }
1019
+
1020
+ return { errors, warnings };
1021
+ }
1022
+
1023
+ function validateImplementationControlCycle(cyclePath) {
1024
+ const errors = [];
1025
+ const warnings = [];
1026
+ const result = readJson(cyclePath);
1027
+ const label = "implementation_control_cycle";
1028
+
1029
+ requireString(result, "schema_version", label, errors);
1030
+ requireString(result, "id", label, errors);
1031
+ requireString(result, "profile", label, errors);
1032
+ requireString(result, "public_safety", label, errors);
1033
+ requireJsonArray(result, "cycles", label, errors);
1034
+ requireJsonArray(result, "cycle_transitions", label, errors);
1035
+ requireArray(result, "kaizen_finding_taxonomy", label, errors);
1036
+ requireArray(result, "kaizen_blocking_findings", label, errors);
1037
+ requireString(result, "kaizen_default_rule", label, errors);
1038
+ requireArray(result, "boundaries", label, errors);
1039
+ requireArray(result, "limitations", label, errors);
1040
+
1041
+ if (result.profile !== undefined && result.profile !== "implementation_control") {
1042
+ errors.push(`${label}.profile must be implementation_control`);
1043
+ }
1044
+ if (result.public_safety !== undefined && result.public_safety !== "synthetic_public") {
1045
+ errors.push(`${label}.public_safety must be synthetic_public`);
1046
+ }
1047
+
1048
+ const requiredCycleIds = new Set([
1049
+ "human_projection_feedback",
1050
+ "implementation_planning",
1051
+ "bounded_work_batch",
1052
+ "review_and_evidence",
1053
+ "release_or_publish",
1054
+ "runtime_feedback",
1055
+ "kaizen_improvement"
1056
+ ]);
1057
+ const requiredTransitionFields = [
1058
+ "from",
1059
+ "to",
1060
+ "trigger",
1061
+ "required_outputs",
1062
+ "required_gates",
1063
+ "handoff_artifact",
1064
+ "owner",
1065
+ "failure_behavior",
1066
+ "recovery_behavior"
1067
+ ];
1068
+ const requiredTransitions = [
1069
+ ["human_projection_feedback", "implementation_planning", "equilibrium_reached"],
1070
+ ["human_projection_feedback", "kaizen_improvement", "cycle_completed"],
1071
+ ["implementation_planning", "bounded_work_batch", "launch_record_ready"],
1072
+ ["implementation_planning", "kaizen_improvement", "cycle_completed"],
1073
+ ["bounded_work_batch", "review_and_evidence", "evidence_ready"],
1074
+ ["bounded_work_batch", "kaizen_improvement", "cycle_completed"],
1075
+ ["review_and_evidence", "release_or_publish", "review_approved"],
1076
+ ["review_and_evidence", "human_projection_feedback", "baseline_gap_found"],
1077
+ ["review_and_evidence", "kaizen_improvement", "cycle_completed"],
1078
+ ["release_or_publish", "runtime_feedback", "released_or_published"],
1079
+ ["release_or_publish", "kaizen_improvement", "cycle_completed"],
1080
+ ["runtime_feedback", "human_projection_feedback", "graph_or_projection_improvement_required"],
1081
+ ["runtime_feedback", "implementation_planning", "implementation_change_required"],
1082
+ ["runtime_feedback", "kaizen_improvement", "cycle_completed"],
1083
+ ["kaizen_improvement", "human_projection_feedback", "graph_or_projection_improvement_required"],
1084
+ ["kaizen_improvement", "implementation_planning", "planning_improvement_required"],
1085
+ ["kaizen_improvement", "bounded_work_batch", "implementation_rework_required"],
1086
+ ["kaizen_improvement", "runtime_feedback", "runtime_evidence_required"]
1087
+ ];
1088
+ const requiredKaizenFindings = [
1089
+ "artifact_improvement",
1090
+ "graph_spec_improvement",
1091
+ "process_improvement",
1092
+ "validator_improvement",
1093
+ "tooling_improvement",
1094
+ "dna_alignment_issue",
1095
+ "quality_regression",
1096
+ "safety_regression",
1097
+ "critical_drift",
1098
+ "user_value_gap"
1099
+ ];
1100
+ const requiredBlockingFindings = [
1101
+ "safety_regression",
1102
+ "quality_regression",
1103
+ "dna_alignment_issue",
1104
+ "critical_drift"
1105
+ ];
1106
+ const cycleIds = new Set();
1107
+ const forbiddenAutoUpdateTerms = [
1108
+ "automatic canonical update",
1109
+ "automatically updates canonical",
1110
+ "auto canonical update",
1111
+ "feedback directly updates",
1112
+ "evidence is approval"
1113
+ ];
1114
+
1115
+ if (Array.isArray(result.cycles)) {
1116
+ for (const [index, cycle] of result.cycles.entries()) {
1117
+ const cycleLabel = `${label}.cycles[${index}]`;
1118
+ requireString(cycle, "id", cycleLabel, errors);
1119
+ requireString(cycle, "purpose", cycleLabel, errors);
1120
+ requireArray(cycle, "stages", cycleLabel, errors);
1121
+ requireArray(cycle, "inputs", cycleLabel, errors);
1122
+ requireArray(cycle, "outputs", cycleLabel, errors);
1123
+ requireArray(cycle, "gates", cycleLabel, errors);
1124
+ requireArray(cycle, "validators", cycleLabel, errors);
1125
+ requireString(cycle, "recovery_behavior", cycleLabel, errors);
1126
+ requireString(cycle, "repeat_condition", cycleLabel, errors);
1127
+ requireString(cycle, "promotion_path", cycleLabel, errors);
1128
+ requireArray(cycle, "evidence_refs", cycleLabel, errors);
1129
+ requireArray(cycle, "limitations", cycleLabel, errors);
1130
+
1131
+ if (typeof cycle.id === "string") {
1132
+ if (cycleIds.has(cycle.id)) {
1133
+ errors.push(`${cycleLabel}.id duplicates ${cycle.id}`);
1134
+ }
1135
+ cycleIds.add(cycle.id);
1136
+ }
1137
+
1138
+ if (Array.isArray(cycle.stages) && cycle.stages.length < 2) {
1139
+ errors.push(`${cycleLabel}.stages must contain at least two stages`);
1140
+ }
1141
+ if (Array.isArray(cycle.gates) && cycle.gates.length === 0) {
1142
+ errors.push(`${cycleLabel}.gates must not be empty`);
1143
+ }
1144
+ if (Array.isArray(cycle.validators) && cycle.validators.length === 0) {
1145
+ errors.push(`${cycleLabel}.validators must not be empty`);
1146
+ }
1147
+ if (Array.isArray(cycle.evidence_refs) && cycle.evidence_refs.length === 0) {
1148
+ errors.push(`${cycleLabel}.evidence_refs must not be empty`);
1149
+ }
1150
+
1151
+ const cycleText = JSON.stringify(cycle).toLowerCase();
1152
+ for (const forbiddenTerm of forbiddenAutoUpdateTerms) {
1153
+ if (cycleText.includes(forbiddenTerm)) {
1154
+ errors.push(`${cycleLabel} contains forbidden auto-update semantics: ${forbiddenTerm}`);
1155
+ }
1156
+ }
1157
+ }
1158
+ }
1159
+
1160
+ for (const requiredCycleId of requiredCycleIds) {
1161
+ if (!cycleIds.has(requiredCycleId)) {
1162
+ errors.push(`${label}.cycles is missing required cycle ${requiredCycleId}`);
1163
+ }
1164
+ }
1165
+
1166
+ if (Array.isArray(result.cycle_transitions)) {
1167
+ const transitionKeys = new Set();
1168
+ for (const [index, transition] of result.cycle_transitions.entries()) {
1169
+ const transitionLabel = `${label}.cycle_transitions[${index}]`;
1170
+
1171
+ for (const field of requiredTransitionFields) {
1172
+ if (["required_outputs", "required_gates"].includes(field)) {
1173
+ requireArray(transition, field, transitionLabel, errors);
1174
+ if (Array.isArray(transition[field]) && transition[field].length === 0) {
1175
+ errors.push(`${transitionLabel}.${field} must not be empty`);
1176
+ }
1177
+ } else {
1178
+ requireString(transition, field, transitionLabel, errors);
1179
+ }
1180
+ }
1181
+
1182
+ if (typeof transition.from === "string" && !cycleIds.has(transition.from)) {
1183
+ errors.push(`${transitionLabel}.from references unknown cycle ${transition.from}`);
1184
+ }
1185
+ if (typeof transition.to === "string" && !cycleIds.has(transition.to)) {
1186
+ errors.push(`${transitionLabel}.to references unknown cycle ${transition.to}`);
1187
+ }
1188
+
1189
+ const transitionKey = `${transition.from ?? "?"}->${transition.to ?? "?"}:${transition.trigger ?? "?"}`;
1190
+ if (transitionKeys.has(transitionKey)) {
1191
+ errors.push(`${transitionLabel} duplicates transition ${transitionKey}`);
1192
+ }
1193
+ transitionKeys.add(transitionKey);
1194
+
1195
+ const transitionText = JSON.stringify(transition).toLowerCase();
1196
+ for (const forbiddenTerm of forbiddenAutoUpdateTerms) {
1197
+ if (transitionText.includes(forbiddenTerm)) {
1198
+ errors.push(`${transitionLabel} contains forbidden auto-update semantics: ${forbiddenTerm}`);
1199
+ }
1200
+ }
1201
+ }
1202
+
1203
+ for (const [from, to, trigger] of requiredTransitions) {
1204
+ const transitionKey = `${from}->${to}:${trigger}`;
1205
+ if (!transitionKeys.has(transitionKey)) {
1206
+ errors.push(`${label}.cycle_transitions is missing required transition ${transitionKey}`);
1207
+ }
1208
+ }
1209
+
1210
+ for (const cycleId of requiredCycleIds) {
1211
+ if (cycleId === "kaizen_improvement") {
1212
+ continue;
1213
+ }
1214
+ const transitionKey = `${cycleId}->kaizen_improvement:cycle_completed`;
1215
+ if (!transitionKeys.has(transitionKey)) {
1216
+ errors.push(`${label}.cycle_transitions must route ${cycleId} to kaizen_improvement on cycle_completed`);
1217
+ }
1218
+ }
1219
+ }
1220
+
1221
+ if (Array.isArray(result.kaizen_finding_taxonomy)) {
1222
+ for (const finding of requiredKaizenFindings) {
1223
+ if (!result.kaizen_finding_taxonomy.includes(finding)) {
1224
+ errors.push(`${label}.kaizen_finding_taxonomy is missing ${finding}`);
1225
+ }
1226
+ }
1227
+ }
1228
+
1229
+ if (Array.isArray(result.kaizen_blocking_findings)) {
1230
+ for (const finding of requiredBlockingFindings) {
1231
+ if (!result.kaizen_blocking_findings.includes(finding)) {
1232
+ errors.push(`${label}.kaizen_blocking_findings is missing ${finding}`);
1233
+ }
1234
+ }
1235
+ }
1236
+
1237
+ const kaizenRule = typeof result.kaizen_default_rule === "string" ? result.kaizen_default_rule.toLowerCase() : "";
1238
+ for (const expectedTerm of ["safety", "quality", "dna", "critical drift"]) {
1239
+ if (kaizenRule && !kaizenRule.includes(expectedTerm)) {
1240
+ warnings.push(`${label}.kaizen_default_rule should mention ${expectedTerm}`);
1241
+ }
1242
+ }
1243
+
1244
+ if (Array.isArray(result.boundaries)) {
1245
+ const boundaryText = result.boundaries.join("\n").toLowerCase();
1246
+ const requiredBoundaries = [
1247
+ "generated",
1248
+ "evidence",
1249
+ "feedback",
1250
+ "proposal",
1251
+ "ready"
1252
+ ];
1253
+ for (const requiredBoundary of requiredBoundaries) {
1254
+ if (!boundaryText.includes(requiredBoundary)) {
1255
+ warnings.push(`${label}.boundaries should mention ${requiredBoundary}`);
1256
+ }
1257
+ }
1258
+ }
1259
+
1260
+ return { errors, warnings };
1261
+ }
1262
+
1263
+ function validateCharacterLayerIntegration(resultPath) {
1264
+ const errors = [];
1265
+ const warnings = [];
1266
+ const result = readJson(resultPath);
1267
+ const label = "character_layer_integration";
1268
+
1269
+ requireString(result, "schema_version", label, errors);
1270
+ requireString(result, "profile", label, errors);
1271
+ requireString(result, "public_safety", label, errors);
1272
+ requireString(result, "integration_id", label, errors);
1273
+ requireString(result, "character_package_ref", label, errors);
1274
+ requireArray(result, "required_gates", label, errors);
1275
+ requireArray(result, "evidence_refs", label, errors);
1276
+ requireArray(result, "limitations", label, errors);
1277
+ requireJsonArray(result, "ai_employee_links", label, errors);
1278
+ requireObject(result, "process_control_links", label, errors);
1279
+ requireObject(result, "runtime_context_boundary", label, errors);
1280
+
1281
+ if (result.profile !== undefined && result.profile !== "character_layer") {
1282
+ errors.push(`${label}.profile must be character_layer`);
1283
+ }
1284
+ if (result.public_safety !== undefined && result.public_safety !== "synthetic_public") {
1285
+ errors.push(`${label}.public_safety must be synthetic_public`);
1286
+ }
1287
+
1288
+ if (Array.isArray(result.ai_employee_links)) {
1289
+ result.ai_employee_links.forEach((link, index) => {
1290
+ const linkLabel = `${label}.ai_employee_links[${index}]`;
1291
+ requireString(link, "ai_employee_ref", linkLabel, errors);
1292
+ requireString(link, "role_ref", linkLabel, errors);
1293
+ requireString(link, "role_character_profile_ref", linkLabel, errors);
1294
+ requireArray(link, "composition_relations", linkLabel, errors);
1295
+ const relationText = Array.isArray(link.composition_relations) ? link.composition_relations.join("\n") : "";
1296
+ for (const requiredRelation of ["governs_role", "governs_employee", "specializes_character", "uses_reflection_protocol"]) {
1297
+ if (!relationText.includes(requiredRelation)) {
1298
+ errors.push(`${linkLabel}.composition_relations must include ${requiredRelation}`);
1299
+ }
1300
+ }
1301
+ });
1302
+ }
1303
+
1304
+ if (result.process_control_links && typeof result.process_control_links === "object") {
1305
+ for (const field of [
1306
+ "launch_record_ref",
1307
+ "process_control_contract_ref",
1308
+ "technology_quality_feedback_ref"
1309
+ ]) {
1310
+ requireString(result.process_control_links, field, `${label}.process_control_links`, errors);
1311
+ }
1312
+ requireArray(result.process_control_links, "transition_gate_refs", `${label}.process_control_links`, errors);
1313
+ }
1314
+
1315
+ if (result.runtime_context_boundary && typeof result.runtime_context_boundary === "object") {
1316
+ for (const field of [
1317
+ "generated_context_ref",
1318
+ "reflection_protocol_ref",
1319
+ "authorization_boundary",
1320
+ "canonical_update_boundary"
1321
+ ]) {
1322
+ requireString(result.runtime_context_boundary, field, `${label}.runtime_context_boundary`, errors);
1323
+ }
1324
+ }
1325
+
1326
+ const gateText = Array.isArray(result.required_gates) ? result.required_gates.join("\n") : "";
1327
+ for (const requiredGate of [
1328
+ "human_review_before_canonical_write",
1329
+ "approval_before_external_action",
1330
+ "technology_quality_feedback"
1331
+ ]) {
1332
+ if (!gateText.includes(requiredGate)) {
1333
+ errors.push(`${label}.required_gates must include ${requiredGate}`);
1334
+ }
1335
+ }
1336
+
1337
+ const resultText = JSON.stringify(result).toLowerCase();
1338
+ for (const forbiddenTerm of [
1339
+ "/users/rim/documents/" + "github/",
1340
+ "simai private",
1341
+ "private runtime " + "trace",
1342
+ "generated context authorizes",
1343
+ "evidence authorizes",
1344
+ "feedback automatically updates",
1345
+ "automatic canonical update",
1346
+ "grants tool permission",
1347
+ "can bypass approval"
1348
+ ]) {
1349
+ if (resultText.includes(forbiddenTerm)) {
1350
+ errors.push(`${label} contains forbidden integration boundary term: ${forbiddenTerm}`);
1351
+ }
1352
+ }
1353
+
1354
+ for (const requiredBoundary of [
1355
+ "does not authorize",
1356
+ "owner review",
1357
+ "canonical"
1358
+ ]) {
1359
+ if (!resultText.includes(requiredBoundary)) {
1360
+ warnings.push(`${label} should mention ${requiredBoundary}`);
1361
+ }
1362
+ }
1363
+
1364
+ return { errors, warnings, result };
1365
+ }
1366
+
1367
+ function validateModelPortabilityEvidence(resultPath) {
1368
+ const errors = [];
1369
+ const warnings = [];
1370
+ const result = readJson(resultPath);
1371
+ const label = "model_portability_evidence";
1372
+
1373
+ requireString(result, "schema_version", label, errors);
1374
+ requireString(result, "profile", label, errors);
1375
+ requireString(result, "public_safety", label, errors);
1376
+ requireString(result, "evidence_id", label, errors);
1377
+ requireString(result, "character_profile_ref", label, errors);
1378
+ requireString(result, "task_set_ref", label, errors);
1379
+ requireString(result, "comparison_verdict", label, errors);
1380
+ requireArray(result, "evidence_refs", label, errors);
1381
+ requireArray(result, "limitations", label, errors);
1382
+ requireJsonArray(result, "model_runs", label, errors);
1383
+ requireObject(result, "comparison_metrics", label, errors);
1384
+
1385
+ if (result.profile !== undefined && result.profile !== "character_layer") {
1386
+ errors.push(`${label}.profile must be character_layer`);
1387
+ }
1388
+ if (result.public_safety !== undefined && result.public_safety !== "synthetic_public") {
1389
+ errors.push(`${label}.public_safety must be synthetic_public`);
1390
+ }
1391
+
1392
+ const verdicts = new Set([
1393
+ "portable_within_fixture_limits",
1394
+ "needs_review",
1395
+ "regressed",
1396
+ "insufficient_evidence"
1397
+ ]);
1398
+ if (typeof result.comparison_verdict === "string" && !verdicts.has(result.comparison_verdict)) {
1399
+ errors.push(`${label}.comparison_verdict has unsupported value ${result.comparison_verdict}`);
1400
+ }
1401
+
1402
+ if (Array.isArray(result.model_runs)) {
1403
+ if (result.model_runs.length < 2) {
1404
+ errors.push(`${label}.model_runs must include at least two model runs`);
1405
+ }
1406
+ result.model_runs.forEach((run, index) => {
1407
+ const runLabel = `${label}.model_runs[${index}]`;
1408
+ requireString(run, "model_ref", runLabel, errors);
1409
+ requireString(run, "run_ref", runLabel, errors);
1410
+ requireString(run, "notes", runLabel, errors);
1411
+ requireArray(run, "passed_fixtures", runLabel, errors);
1412
+ requireArray(run, "failed_fixtures", runLabel, errors);
1413
+ requireArray(run, "boundary_violations", runLabel, errors);
1414
+ });
1415
+ }
1416
+
1417
+ if (result.comparison_metrics && typeof result.comparison_metrics === "object") {
1418
+ for (const metric of [
1419
+ "boundary_violation_delta",
1420
+ "false_completion_claim_delta",
1421
+ "evidence_authorization_confusion_delta",
1422
+ "feedback_update_confusion_delta",
1423
+ "blocker_reporting_delta",
1424
+ "escalation_correctness_delta"
1425
+ ]) {
1426
+ if (typeof result.comparison_metrics[metric] !== "number") {
1427
+ errors.push(`${label}.comparison_metrics.${metric} must be a number`);
1428
+ }
1429
+ }
1430
+ }
1431
+
1432
+ const resultText = JSON.stringify(result).toLowerCase();
1433
+ for (const forbiddenTerm of [
1434
+ "/users/rim/documents/" + "github/",
1435
+ "simai private",
1436
+ "private runtime " + "trace",
1437
+ "proves model equivalence",
1438
+ "guarantees model replacement",
1439
+ "production-ready replacement",
1440
+ "no review required"
1441
+ ]) {
1442
+ if (resultText.includes(forbiddenTerm)) {
1443
+ errors.push(`${label} contains forbidden portability claim: ${forbiddenTerm}`);
1444
+ }
1445
+ }
1446
+
1447
+ for (const requiredLimit of ["synthetic", "does not prove", "model-dependent"]) {
1448
+ if (!resultText.includes(requiredLimit)) {
1449
+ warnings.push(`${label}.limitations should mention ${requiredLimit}`);
1450
+ }
1451
+ }
1452
+
1453
+ return { errors, warnings, result };
1454
+ }
1455
+
1456
+ function validateCharacterLayerReadiness(resultPath) {
1457
+ const errors = [];
1458
+ const warnings = [];
1459
+ const result = readJson(resultPath);
1460
+ const label = "character_layer_readiness";
1461
+
1462
+ requireString(result, "schema_version", label, errors);
1463
+ requireString(result, "profile", label, errors);
1464
+ requireString(result, "public_safety", label, errors);
1465
+ requireString(result, "readiness_id", label, errors);
1466
+ requireString(result, "target_release_track", label, errors);
1467
+ requireString(result, "readiness_verdict", label, errors);
1468
+ requireArray(result, "validation_commands", label, errors);
1469
+ requireArray(result, "evidence_refs", label, errors);
1470
+ requireArray(result, "claim_boundaries", label, errors);
1471
+ requireArray(result, "remaining_limits", label, errors);
1472
+ requireJsonArray(result, "completed_capabilities", label, errors);
1473
+
1474
+ if (result.profile !== undefined && result.profile !== "character_layer") {
1475
+ errors.push(`${label}.profile must be character_layer`);
1476
+ }
1477
+ if (result.public_safety !== undefined && result.public_safety !== "synthetic_public") {
1478
+ errors.push(`${label}.public_safety must be synthetic_public`);
1479
+ }
1480
+
1481
+ const verdicts = new Set([
1482
+ "ready_for_1_0_candidate",
1483
+ "needs_hardening",
1484
+ "blocked",
1485
+ "insufficient_evidence"
1486
+ ]);
1487
+ if (typeof result.readiness_verdict === "string" && !verdicts.has(result.readiness_verdict)) {
1488
+ errors.push(`${label}.readiness_verdict has unsupported value ${result.readiness_verdict}`);
1489
+ }
1490
+
1491
+ const completedIds = new Set();
1492
+ if (Array.isArray(result.completed_capabilities)) {
1493
+ result.completed_capabilities.forEach((capability, index) => {
1494
+ const capLabel = `${label}.completed_capabilities[${index}]`;
1495
+ requireString(capability, "id", capLabel, errors);
1496
+ requireString(capability, "status", capLabel, errors);
1497
+ requireArray(capability, "evidence_refs", capLabel, errors);
1498
+ if (capability.status !== undefined && !["completed", "partial", "missing"].includes(capability.status)) {
1499
+ errors.push(`${capLabel}.status has unsupported value ${capability.status}`);
1500
+ }
1501
+ if (capability.status === "completed" && typeof capability.id === "string") {
1502
+ completedIds.add(capability.id);
1503
+ }
1504
+ });
1505
+ }
1506
+
1507
+ for (const requiredCapability of [
1508
+ "profile_vocabulary",
1509
+ "minimal_fixture",
1510
+ "starter_pack",
1511
+ "semantic_negative_fixtures",
1512
+ "cross_layer_integration",
1513
+ "model_portability_evidence_shape"
1514
+ ]) {
1515
+ if (!completedIds.has(requiredCapability)) {
1516
+ errors.push(`${label}.completed_capabilities must include completed ${requiredCapability}`);
1517
+ }
1518
+ }
1519
+
1520
+ const commandText = Array.isArray(result.validation_commands) ? result.validation_commands.join("\n") : "";
1521
+ for (const requiredCommand of [
1522
+ "validate:character-layer",
1523
+ "validate:character-layer-starter",
1524
+ "validate:character-layer-integration",
1525
+ "validate:model-portability-evidence",
1526
+ "test:character-layer-semantic-negative",
1527
+ "npm test",
1528
+ "release:check"
1529
+ ]) {
1530
+ if (!commandText.includes(requiredCommand)) {
1531
+ errors.push(`${label}.validation_commands must include ${requiredCommand}`);
1532
+ }
1533
+ }
1534
+
1535
+ const resultText = JSON.stringify(result).toLowerCase();
1536
+ for (const forbiddenTerm of [
1537
+ "/users/rim/documents/" + "github/",
1538
+ "simai private",
1539
+ "private runtime " + "trace",
1540
+ "proves broad model equivalence",
1541
+ "guarantees model replacement",
1542
+ "production autonomous execution safety is proven",
1543
+ "peer-reviewed proof"
1544
+ ]) {
1545
+ if (resultText.includes(forbiddenTerm)) {
1546
+ errors.push(`${label} contains forbidden readiness claim: ${forbiddenTerm}`);
1547
+ }
1548
+ }
1549
+
1550
+ for (const requiredBoundary of [
1551
+ "does not prove",
1552
+ "not authorize canonical updates",
1553
+ "no peer-reviewed scientific proof",
1554
+ "model replacement"
1555
+ ]) {
1556
+ if (!resultText.includes(requiredBoundary)) {
1557
+ warnings.push(`${label} should mention ${requiredBoundary}`);
1558
+ }
1559
+ }
1560
+
1561
+ return { errors, warnings, result };
1562
+ }
1563
+
1564
+ function validatePublicImplementationControlResult(resultPath, mode) {
1565
+ const errors = [];
1566
+ const warnings = [];
1567
+ const result = readJson(resultPath);
1568
+ const label = mode.replace(/-/g, "_");
1569
+
1570
+ requireString(result, "schema_version", label, errors);
1571
+ requireString(result, "id", label, errors);
1572
+ requireString(result, "profile", label, errors);
1573
+ requireString(result, "public_safety", label, errors);
1574
+ requireArray(result, "evidence_refs", label, errors);
1575
+ requireArray(result, "limitations", label, errors);
1576
+
1577
+ if (result.profile !== undefined && result.profile !== "implementation_control") {
1578
+ errors.push(`${label}.profile must be implementation_control`);
1579
+ }
1580
+ if (result.public_safety !== undefined && result.public_safety !== "synthetic_public") {
1581
+ errors.push(`${label}.public_safety must be synthetic_public`);
1582
+ }
1583
+
1584
+ const resultText = JSON.stringify(result).toLowerCase();
1585
+ const forbiddenTerms = [
1586
+ "/users/rim/documents/" + "github/",
1587
+ "lar" + "ena",
1588
+ "simai private",
1589
+ "source/" + "workflow",
1590
+ "private runtime " + "trace",
1591
+ "automatic canonical update",
1592
+ "feedback directly updates",
1593
+ "evidence is approval"
1594
+ ];
1595
+ for (const forbiddenTerm of forbiddenTerms) {
1596
+ if (resultText.includes(forbiddenTerm)) {
1597
+ errors.push(`${label} contains forbidden public-transfer term: ${forbiddenTerm}`);
1598
+ }
1599
+ }
1600
+
1601
+ if (mode === "graph-dna-alignment") {
1602
+ requireObject(result, "parent_dna", label, errors);
1603
+ requireObject(result, "component_dna", label, errors);
1604
+ requireObject(result, "alignment", label, errors);
1605
+ if (result.parent_dna && typeof result.parent_dna === "object") {
1606
+ requireString(result.parent_dna, "mission", `${label}.parent_dna`, errors);
1607
+ requireString(result.parent_dna, "evolution_vector", `${label}.parent_dna`, errors);
1608
+ requireArray(result.parent_dna, "non_negotiable_principles", `${label}.parent_dna`, errors);
1609
+ }
1610
+ if (result.component_dna && typeof result.component_dna === "object") {
1611
+ requireArray(result.component_dna, "owns", `${label}.component_dna`, errors);
1612
+ requireArray(result.component_dna, "must_not_own", `${label}.component_dna`, errors);
1613
+ requireArray(result.component_dna, "invariants", `${label}.component_dna`, errors);
1614
+ requireArray(result.component_dna, "success_criteria", `${label}.component_dna`, errors);
1615
+ requireArray(result.component_dna, "anti_patterns", `${label}.component_dna`, errors);
1616
+ }
1617
+ if (result.alignment && typeof result.alignment === "object" && typeof result.alignment.proposal_required !== "boolean") {
1618
+ errors.push(`${label}.alignment.proposal_required must be a boolean`);
1619
+ }
1620
+ }
1621
+
1622
+ if (mode === "work-state-machine") {
1623
+ requireArray(result, "states", label, errors);
1624
+ requireJsonArray(result, "transitions", label, errors);
1625
+ requireArray(result, "false_transition_guards", label, errors);
1626
+ const stateText = Array.isArray(result.states) ? result.states.join("\n") : "";
1627
+ for (const requiredState of ["planned", "ready_to_execute", "evidence_recorded", "sync_proposed", "approved"]) {
1628
+ if (!stateText.includes(requiredState)) {
1629
+ errors.push(`${label}.states must include ${requiredState}`);
1630
+ }
1631
+ }
1632
+ const guardText = Array.isArray(result.false_transition_guards) ? result.false_transition_guards.join("\n").toLowerCase() : "";
1633
+ for (const requiredGuard of ["ready", "written", "sync"]) {
1634
+ if (!guardText.includes(requiredGuard)) {
1635
+ warnings.push(`${label}.false_transition_guards should mention ${requiredGuard}`);
1636
+ }
1637
+ }
1638
+ }
1639
+
1640
+ if (mode === "launch-record") {
1641
+ for (const field of [
1642
+ "workflow_id",
1643
+ "process_model_id",
1644
+ "cycle_id",
1645
+ "current_state",
1646
+ "target_state",
1647
+ "owner_role"
1648
+ ]) {
1649
+ requireString(result, field, label, errors);
1650
+ }
1651
+ for (const field of [
1652
+ "allowed_files",
1653
+ "forbidden_files",
1654
+ "allowed_actions",
1655
+ "required_gates",
1656
+ "required_evidence",
1657
+ "stop_conditions"
1658
+ ]) {
1659
+ requireArray(result, field, label, errors);
1660
+ }
1661
+ if (typeof result.approved_by_user !== "boolean") {
1662
+ errors.push(`${label}.approved_by_user must be a boolean`);
1663
+ }
1664
+ const launchText = JSON.stringify(result).toLowerCase();
1665
+ for (const requiredBoundary of ["not execution", "not implementation", "not approval", "not release"]) {
1666
+ if (!launchText.includes(requiredBoundary)) {
1667
+ warnings.push(`${label}.limitations should mention ${requiredBoundary}`);
1668
+ }
1669
+ }
1670
+ }
1671
+
1672
+ if (mode === "process-control-contract") {
1673
+ for (const field of ["process_id", "cycle_id", "state_machine_id", "recovery_behavior"]) {
1674
+ requireString(result, field, label, errors);
1675
+ }
1676
+ requireObject(result, "launch_record_policy", label, errors);
1677
+ requireObject(result, "kaizen_policy", label, errors);
1678
+ requireArray(result, "evidence_requirements", label, errors);
1679
+ requireArray(result, "risk_controls", label, errors);
1680
+ requireArray(result, "validators", label, errors);
1681
+
1682
+ if (result.launch_record_policy && typeof result.launch_record_policy === "object") {
1683
+ requireArray(result.launch_record_policy, "required_for_states", `${label}.launch_record_policy`, errors);
1684
+ requireArray(result.launch_record_policy, "required_for_transitions", `${label}.launch_record_policy`, errors);
1685
+ if (typeof result.launch_record_policy.approval_required !== "boolean") {
1686
+ errors.push(`${label}.launch_record_policy.approval_required must be a boolean`);
1687
+ }
1688
+ }
1689
+
1690
+ if (result.kaizen_policy && typeof result.kaizen_policy === "object") {
1691
+ if (result.kaizen_policy.terminal_state_requires_review_or_skip !== true) {
1692
+ errors.push(`${label}.kaizen_policy.terminal_state_requires_review_or_skip must be true`);
1693
+ }
1694
+ requireString(result.kaizen_policy, "accepted_skip_field", `${label}.kaizen_policy`, errors);
1695
+ }
1696
+
1697
+ if (result.technology_quality_feedback_policy !== undefined) {
1698
+ requireObject(result, "technology_quality_feedback_policy", label, errors);
1699
+ if (result.technology_quality_feedback_policy && typeof result.technology_quality_feedback_policy === "object") {
1700
+ requireArray(result.technology_quality_feedback_policy, "required_for_transitions", `${label}.technology_quality_feedback_policy`, errors);
1701
+ requireArray(result.technology_quality_feedback_policy, "accepted_verdicts", `${label}.technology_quality_feedback_policy`, errors);
1702
+ if (result.technology_quality_feedback_policy.blocking_findings_stop_transition !== true) {
1703
+ errors.push(`${label}.technology_quality_feedback_policy.blocking_findings_stop_transition must be true`);
1704
+ }
1705
+ }
1706
+ }
1707
+
1708
+ const validatorText = Array.isArray(result.validators) ? result.validators.join("\n") : "";
1709
+ for (const requiredValidator of ["launch-record", "process-transition"]) {
1710
+ if (!validatorText.includes(requiredValidator)) {
1711
+ errors.push(`${label}.validators must include ${requiredValidator}`);
1712
+ }
1713
+ }
1714
+ if (
1715
+ result.technology_quality_feedback_policy !== undefined &&
1716
+ !validatorText.includes("technology-quality-feedback")
1717
+ ) {
1718
+ errors.push(`${label}.validators must include technology-quality-feedback when technology_quality_feedback_policy is present`);
1719
+ }
1720
+ }
1721
+
1722
+ if (mode === "technology-quality-feedback") {
1723
+ const classifications = new Set([
1724
+ "accepted",
1725
+ "work_fix_required",
1726
+ "test_gap",
1727
+ "spec_gap",
1728
+ "graph_update_proposal",
1729
+ "process_improvement",
1730
+ "release_blocker",
1731
+ "security_blocker",
1732
+ "defer_with_reason"
1733
+ ]);
1734
+ const verdicts = new Set([
1735
+ "accepted",
1736
+ "accepted_with_deferred_items",
1737
+ "changes_requested",
1738
+ "blocked_by_spec_gap",
1739
+ "blocked_by_security",
1740
+ "blocked_by_missing_evidence",
1741
+ "release_not_ready"
1742
+ ]);
1743
+ const severities = new Set(["critical", "high", "medium", "low"]);
1744
+ const acceptedVerdicts = new Set(["accepted", "accepted_with_deferred_items"]);
1745
+
1746
+ for (const field of ["technology_ref", "process_id", "launch_record_ref", "verdict", "next_transition"]) {
1747
+ requireString(result, field, label, errors);
1748
+ }
1749
+ for (const field of [
1750
+ "work_evidence_refs",
1751
+ "required_steps",
1752
+ "completed_steps",
1753
+ "missing_steps",
1754
+ "review_dimensions",
1755
+ "feedback_classification",
1756
+ "blocking_findings",
1757
+ "kaizen_refs"
1758
+ ]) {
1759
+ requireArray(result, field, label, errors);
1760
+ }
1761
+ requireJsonArray(result, "findings", label, errors);
1762
+
1763
+ if (typeof result.verdict === "string" && !verdicts.has(result.verdict)) {
1764
+ errors.push(`${label}.verdict has unsupported value ${result.verdict}`);
1765
+ }
1766
+
1767
+ const completedSteps = new Set(Array.isArray(result.completed_steps) ? result.completed_steps : []);
1768
+ if (Array.isArray(result.required_steps)) {
1769
+ for (const requiredStep of result.required_steps) {
1770
+ if (!completedSteps.has(requiredStep)) {
1771
+ errors.push(`${label}.completed_steps is missing required step ${requiredStep}`);
1772
+ }
1773
+ }
1774
+ }
1775
+ if (Array.isArray(result.missing_steps) && result.missing_steps.length > 0) {
1776
+ errors.push(`${label}.missing_steps must be empty for a passing feedback report`);
1777
+ }
1778
+
1779
+ const feedbackClassifications = new Set(Array.isArray(result.feedback_classification) ? result.feedback_classification : []);
1780
+ if (Array.isArray(result.feedback_classification)) {
1781
+ for (const classification of result.feedback_classification) {
1782
+ if (!classifications.has(classification)) {
1783
+ errors.push(`${label}.feedback_classification has unsupported value ${classification}`);
1784
+ }
1785
+ }
1786
+ }
1787
+
1788
+ const blockingFindingRefs = new Set(Array.isArray(result.blocking_findings) ? result.blocking_findings : []);
1789
+ let hasBlockingFinding = false;
1790
+ let hasProcessImprovement = false;
1791
+ let hasSpecGap = false;
1792
+
1793
+ if (Array.isArray(result.findings)) {
1794
+ for (const [index, finding] of result.findings.entries()) {
1795
+ const findingLabel = `${label}.findings[${index}]`;
1796
+ for (const field of ["id", "dimension", "classification", "severity", "summary", "next_route"]) {
1797
+ requireString(finding, field, findingLabel, errors);
1798
+ }
1799
+ requireArray(finding, "evidence_refs", findingLabel, errors);
1800
+ if (typeof finding.blocking !== "boolean") {
1801
+ errors.push(`${findingLabel}.blocking must be a boolean`);
1802
+ }
1803
+
1804
+ if (typeof finding.classification === "string") {
1805
+ if (!classifications.has(finding.classification)) {
1806
+ errors.push(`${findingLabel}.classification has unsupported value ${finding.classification}`);
1807
+ }
1808
+ if (!feedbackClassifications.has(finding.classification)) {
1809
+ errors.push(`${label}.feedback_classification must include finding classification ${finding.classification}`);
1810
+ }
1811
+ if (finding.classification === "process_improvement") {
1812
+ hasProcessImprovement = true;
1813
+ if (typeof finding.next_route !== "string" || !finding.next_route.toLowerCase().includes("kaizen")) {
1814
+ errors.push(`${findingLabel}.next_route must route process_improvement to Kaizen`);
1815
+ }
1816
+ }
1817
+ if (finding.classification === "spec_gap") {
1818
+ hasSpecGap = true;
1819
+ const route = typeof finding.next_route === "string" ? finding.next_route.toLowerCase() : "";
1820
+ if (!route.includes("planning") && !route.includes("human_projection") && !route.includes("graph_sync")) {
1821
+ errors.push(`${findingLabel}.next_route must route spec_gap to planning, human_projection or graph_sync`);
1822
+ }
1823
+ }
1824
+ if (["release_blocker", "security_blocker"].includes(finding.classification) && finding.blocking !== true) {
1825
+ errors.push(`${findingLabel}.blocking must be true for ${finding.classification}`);
1826
+ }
1827
+ }
1828
+
1829
+ if (finding.blocking === true) {
1830
+ hasBlockingFinding = true;
1831
+ if (typeof finding.id === "string" && !blockingFindingRefs.has(finding.id)) {
1832
+ errors.push(`${label}.blocking_findings must include blocking finding ${finding.id}`);
1833
+ }
1834
+ }
1835
+
1836
+ if (typeof finding.severity === "string" && !severities.has(finding.severity)) {
1837
+ errors.push(`${findingLabel}.severity has unsupported value ${finding.severity}`);
1838
+ }
1839
+ }
1840
+ }
1841
+
1842
+ if (hasProcessImprovement && (!Array.isArray(result.kaizen_refs) || result.kaizen_refs.length === 0)) {
1843
+ errors.push(`${label}.kaizen_refs must not be empty when process_improvement is present`);
1844
+ }
1845
+
1846
+ if (hasSpecGap && typeof result.next_transition === "string") {
1847
+ const transition = result.next_transition.toLowerCase();
1848
+ if (!transition.includes("planning") && !transition.includes("human_projection") && !transition.includes("graph_sync")) {
1849
+ errors.push(`${label}.next_transition must route spec_gap to planning, human_projection or graph_sync`);
1850
+ }
1851
+ }
1852
+
1853
+ if (acceptedVerdicts.has(result.verdict) && (hasBlockingFinding || blockingFindingRefs.size > 0)) {
1854
+ errors.push(`${label}.verdict cannot be accepted while blocking findings are present`);
1855
+ }
1856
+
1857
+ const feedbackText = JSON.stringify(result).toLowerCase();
1858
+ const forbiddenBoundaryTerms = [
1859
+ "evidence is approval",
1860
+ "tests are acceptance",
1861
+ "feedback directly updates",
1862
+ "automatic canonical update",
1863
+ "automatically updates canonical",
1864
+ "proposal is controlled update",
1865
+ "canonical_update"
1866
+ ];
1867
+ for (const forbiddenTerm of forbiddenBoundaryTerms) {
1868
+ if (feedbackText.includes(forbiddenTerm)) {
1869
+ errors.push(`${label} contains forbidden authorization boundary term: ${forbiddenTerm}`);
1870
+ }
1871
+ }
1872
+
1873
+ const limitationText = Array.isArray(result.limitations) ? result.limitations.join("\n").toLowerCase() : "";
1874
+ for (const expectedBoundary of ["tests", "evidence", "canonical", "acceptance"]) {
1875
+ if (!limitationText.includes(expectedBoundary)) {
1876
+ warnings.push(`${label}.limitations should mention ${expectedBoundary}`);
1877
+ }
1878
+ }
1879
+ }
1880
+
1881
+ if (mode === "development-cockpit") {
1882
+ for (const field of ["subject_ref", "generated_at"]) {
1883
+ requireString(result, field, label, errors);
1884
+ }
1885
+ requireJsonArray(result, "instruments", label, errors);
1886
+ requireObject(result, "readiness", label, errors);
1887
+ requireObject(result, "next_best_action", label, errors);
1888
+ requireArray(result, "blocking_rules", label, errors);
1889
+
1890
+ if (result.readiness && typeof result.readiness === "object") {
1891
+ for (const field of [
1892
+ "developer_test_readiness",
1893
+ "product_readiness",
1894
+ "production_readiness",
1895
+ "external_user_testing_readiness"
1896
+ ]) {
1897
+ if (result.readiness[field] === undefined) {
1898
+ errors.push(`${label}.readiness.${field} is required`);
1899
+ }
1900
+ }
1901
+ }
1902
+
1903
+ if (Array.isArray(result.instruments)) {
1904
+ for (const [index, instrument] of result.instruments.entries()) {
1905
+ const instrumentLabel = `${label}.instruments[${index}]`;
1906
+ for (const field of ["id", "family", "band", "status", "reason"]) {
1907
+ requireString(instrument, field, instrumentLabel, errors);
1908
+ }
1909
+ requireArray(instrument, "evidence_refs", instrumentLabel, errors);
1910
+ if (typeof instrument.score !== "number" || instrument.score < 0 || instrument.score > 100) {
1911
+ errors.push(`${instrumentLabel}.score must be a number between 0 and 100`);
1912
+ }
1913
+ if (Array.isArray(instrument.evidence_refs) && instrument.evidence_refs.length === 0) {
1914
+ errors.push(`${instrumentLabel}.evidence_refs must not be empty`);
1915
+ }
1916
+ }
1917
+ }
1918
+
1919
+ if (result.next_best_action && typeof result.next_best_action === "object") {
1920
+ requireString(result.next_best_action, "action", `${label}.next_best_action`, errors);
1921
+ requireString(result.next_best_action, "target_cycle", `${label}.next_best_action`, errors);
1922
+ requireArray(result.next_best_action, "required_gates", `${label}.next_best_action`, errors);
1923
+ requireArray(result.next_best_action, "evidence_refs", `${label}.next_best_action`, errors);
1924
+ if (
1925
+ Array.isArray(result.next_best_action.required_gates) &&
1926
+ result.next_best_action.required_gates.length === 0
1927
+ ) {
1928
+ errors.push(`${label}.next_best_action.required_gates must not be empty`);
1929
+ }
1930
+ }
1931
+
1932
+ const limitationText = Array.isArray(result.limitations) ? result.limitations.join("\n").toLowerCase() : "";
1933
+ for (const expectedBoundary of ["acceptance", "evidence", "canonical", "release"]) {
1934
+ if (!limitationText.includes(expectedBoundary)) {
1935
+ warnings.push(`${label}.limitations should mention ${expectedBoundary}`);
1936
+ }
1937
+ }
1938
+ }
1939
+
1940
+ if (mode === "feature-implementation-traceability") {
1941
+ requireString(result, "subject_ref", label, errors);
1942
+ requireJsonArray(result, "features", label, errors);
1943
+ requireJsonArray(result, "implementation_mappings", label, errors);
1944
+ requireJsonArray(result, "dependency_mappings", label, errors);
1945
+ requireObject(result, "coverage_summary", label, errors);
1946
+
1947
+ const featureIds = new Set();
1948
+ if (Array.isArray(result.features)) {
1949
+ for (const [index, feature] of result.features.entries()) {
1950
+ const featureLabel = `${label}.features[${index}]`;
1951
+ for (const field of ["id", "title", "status", "owner_ref"]) {
1952
+ requireString(feature, field, featureLabel, errors);
1953
+ }
1954
+ requireArray(feature, "evidence_refs", featureLabel, errors);
1955
+ if (typeof feature.id === "string") {
1956
+ featureIds.add(feature.id);
1957
+ }
1958
+ }
1959
+ }
1960
+
1961
+ if (Array.isArray(result.implementation_mappings)) {
1962
+ for (const [index, mapping] of result.implementation_mappings.entries()) {
1963
+ const mappingLabel = `${label}.implementation_mappings[${index}]`;
1964
+ requireString(mapping, "feature_ref", mappingLabel, errors);
1965
+ for (const field of [
1966
+ "implementation_refs",
1967
+ "test_refs",
1968
+ "review_refs",
1969
+ "documentation_refs",
1970
+ "evidence_refs",
1971
+ "known_gaps"
1972
+ ]) {
1973
+ requireArray(mapping, field, mappingLabel, errors);
1974
+ }
1975
+ requireString(mapping, "status", mappingLabel, errors);
1976
+ if (typeof mapping.confidence !== "number" || mapping.confidence < 0 || mapping.confidence > 1) {
1977
+ errors.push(`${mappingLabel}.confidence must be a number between 0 and 1`);
1978
+ }
1979
+ if (typeof mapping.feature_ref === "string" && !featureIds.has(mapping.feature_ref)) {
1980
+ errors.push(`${mappingLabel}.feature_ref references missing feature ${mapping.feature_ref}`);
1981
+ }
1982
+ if (
1983
+ typeof mapping.status === "string" &&
1984
+ ["implemented", "tested", "review_ready", "accepted", "released"].includes(mapping.status) &&
1985
+ (!Array.isArray(mapping.evidence_refs) || mapping.evidence_refs.length === 0)
1986
+ ) {
1987
+ errors.push(`${mappingLabel}.evidence_refs must not be empty for status ${mapping.status}`);
1988
+ }
1989
+ if (
1990
+ typeof mapping.status === "string" &&
1991
+ ["accepted", "released"].includes(mapping.status) &&
1992
+ (!Array.isArray(mapping.review_refs) || mapping.review_refs.length === 0)
1993
+ ) {
1994
+ errors.push(`${mappingLabel}.review_refs must not be empty for status ${mapping.status}`);
1995
+ }
1996
+ }
1997
+ }
1998
+
1999
+ const limitationText = Array.isArray(result.limitations) ? result.limitations.join("\n").toLowerCase() : "";
2000
+ for (const expectedBoundary of ["mapped", "implementation", "acceptance", "release"]) {
2001
+ if (!limitationText.includes(expectedBoundary)) {
2002
+ warnings.push(`${label}.limitations should mention ${expectedBoundary}`);
2003
+ }
2004
+ }
2005
+ }
2006
+
2007
+ if (mode === "multi-source-quality-feedback") {
2008
+ const classifications = new Set([
2009
+ "accepted",
2010
+ "work_fix_required",
2011
+ "test_gap",
2012
+ "spec_gap",
2013
+ "graph_update_proposal",
2014
+ "process_improvement",
2015
+ "release_blocker",
2016
+ "security_blocker",
2017
+ "defer_with_reason"
2018
+ ]);
2019
+ const verdicts = new Set([
2020
+ "accepted_for_transition",
2021
+ "changes_requested",
2022
+ "blocked",
2023
+ "defer_with_reason",
2024
+ "proposal_required"
2025
+ ]);
2026
+ const severities = new Set(["critical", "high", "medium", "low"]);
2027
+
2028
+ requireString(result, "process_id", label, errors);
2029
+ requireJsonArray(result, "sources", label, errors);
2030
+ requireJsonArray(result, "findings", label, errors);
2031
+ for (const field of ["feedback_classification", "blocking_findings", "kaizen_refs"]) {
2032
+ requireArray(result, field, label, errors);
2033
+ }
2034
+ requireString(result, "verdict", label, errors);
2035
+ requireString(result, "next_transition", label, errors);
2036
+
2037
+ if (typeof result.verdict === "string" && !verdicts.has(result.verdict)) {
2038
+ errors.push(`${label}.verdict has unsupported value ${result.verdict}`);
2039
+ }
2040
+
2041
+ if (Array.isArray(result.sources)) {
2042
+ for (const [index, source] of result.sources.entries()) {
2043
+ const sourceLabel = `${label}.sources[${index}]`;
2044
+ for (const field of ["id", "kind", "verdict"]) {
2045
+ requireString(source, field, sourceLabel, errors);
2046
+ }
2047
+ requireArray(source, "evidence_refs", sourceLabel, errors);
2048
+ requireArray(source, "limitations", sourceLabel, errors);
2049
+ if (Array.isArray(source.evidence_refs) && source.evidence_refs.length === 0) {
2050
+ errors.push(`${sourceLabel}.evidence_refs must not be empty`);
2051
+ }
2052
+ }
2053
+ }
2054
+
2055
+ const feedbackClassifications = new Set(Array.isArray(result.feedback_classification) ? result.feedback_classification : []);
2056
+ const blockingFindingRefs = new Set(Array.isArray(result.blocking_findings) ? result.blocking_findings : []);
2057
+ let hasBlockingFinding = false;
2058
+ let hasProcessImprovement = false;
2059
+ let hasSpecGap = false;
2060
+
2061
+ if (Array.isArray(result.findings)) {
2062
+ for (const [index, finding] of result.findings.entries()) {
2063
+ const findingLabel = `${label}.findings[${index}]`;
2064
+ for (const field of ["id", "source_ref", "classification", "severity", "summary", "next_route"]) {
2065
+ requireString(finding, field, findingLabel, errors);
2066
+ }
2067
+ requireArray(finding, "evidence_refs", findingLabel, errors);
2068
+ if (typeof finding.blocking !== "boolean") {
2069
+ errors.push(`${findingLabel}.blocking must be a boolean`);
2070
+ }
2071
+ if (typeof finding.classification === "string") {
2072
+ if (!classifications.has(finding.classification)) {
2073
+ errors.push(`${findingLabel}.classification has unsupported value ${finding.classification}`);
2074
+ }
2075
+ if (!feedbackClassifications.has(finding.classification)) {
2076
+ errors.push(`${label}.feedback_classification must include finding classification ${finding.classification}`);
2077
+ }
2078
+ if (finding.classification === "process_improvement") {
2079
+ hasProcessImprovement = true;
2080
+ if (typeof finding.next_route !== "string" || !finding.next_route.toLowerCase().includes("kaizen")) {
2081
+ errors.push(`${findingLabel}.next_route must route process_improvement to Kaizen`);
2082
+ }
2083
+ }
2084
+ if (finding.classification === "spec_gap") {
2085
+ hasSpecGap = true;
2086
+ const route = typeof finding.next_route === "string" ? finding.next_route.toLowerCase() : "";
2087
+ if (!route.includes("planning") && !route.includes("graph_sync")) {
2088
+ errors.push(`${findingLabel}.next_route must route spec_gap to planning or graph_sync`);
2089
+ }
2090
+ }
2091
+ if (["release_blocker", "security_blocker"].includes(finding.classification) && finding.blocking !== true) {
2092
+ errors.push(`${findingLabel}.blocking must be true for ${finding.classification}`);
2093
+ }
2094
+ }
2095
+ if (finding.blocking === true) {
2096
+ hasBlockingFinding = true;
2097
+ if (typeof finding.id === "string" && !blockingFindingRefs.has(finding.id)) {
2098
+ errors.push(`${label}.blocking_findings must include blocking finding ${finding.id}`);
2099
+ }
2100
+ }
2101
+ if (typeof finding.severity === "string" && !severities.has(finding.severity)) {
2102
+ errors.push(`${findingLabel}.severity has unsupported value ${finding.severity}`);
2103
+ }
2104
+ }
2105
+ }
2106
+
2107
+ if (hasProcessImprovement && (!Array.isArray(result.kaizen_refs) || result.kaizen_refs.length === 0)) {
2108
+ errors.push(`${label}.kaizen_refs must not be empty when process_improvement is present`);
2109
+ }
2110
+ if (hasSpecGap && typeof result.next_transition === "string") {
2111
+ const transition = result.next_transition.toLowerCase();
2112
+ if (!transition.includes("planning") && !transition.includes("graph_sync")) {
2113
+ errors.push(`${label}.next_transition must route spec_gap to planning or graph_sync`);
2114
+ }
2115
+ }
2116
+ if (hasBlockingFinding && result.verdict === "accepted_for_transition") {
2117
+ errors.push(`${label}.verdict cannot be accepted_for_transition while blocking findings are present`);
2118
+ }
2119
+
2120
+ const feedbackText = JSON.stringify(result).toLowerCase();
2121
+ for (const forbiddenTerm of [
2122
+ "tests are acceptance",
2123
+ "evidence is approval",
2124
+ "automatic canonical update",
2125
+ "feedback directly updates",
2126
+ "proposal is controlled update"
2127
+ ]) {
2128
+ if (feedbackText.includes(forbiddenTerm)) {
2129
+ errors.push(`${label} contains forbidden authorization boundary term: ${forbiddenTerm}`);
2130
+ }
2131
+ }
2132
+ }
2133
+
2134
+ if (mode === "recovery-resume-record") {
2135
+ for (const field of [
2136
+ "current_state",
2137
+ "last_good_checkpoint",
2138
+ "target_scope",
2139
+ "last_validation_result",
2140
+ "evidence_status",
2141
+ "next_safe_command",
2142
+ "rollback_option"
2143
+ ]) {
2144
+ requireString(result, field, label, errors);
2145
+ }
2146
+ requireArray(result, "blockers", label, errors);
2147
+ if (typeof result.human_confirmation_required !== "boolean") {
2148
+ errors.push(`${label}.human_confirmation_required must be a boolean`);
2149
+ }
2150
+ }
2151
+
2152
+ if (mode === "risk-control-matrix") {
2153
+ requireJsonArray(result, "risks", label, errors);
2154
+ const severities = new Set(["critical", "high", "medium", "low"]);
2155
+ if (Array.isArray(result.risks)) {
2156
+ for (const [index, risk] of result.risks.entries()) {
2157
+ const riskLabel = `${label}.risks[${index}]`;
2158
+ for (const field of [
2159
+ "id",
2160
+ "severity",
2161
+ "description",
2162
+ "detection_signal",
2163
+ "prevention",
2164
+ "gate_or_validator",
2165
+ "evidence_requirement",
2166
+ "recovery_action",
2167
+ "escalation_rule",
2168
+ "owner_role"
2169
+ ]) {
2170
+ requireString(risk, field, riskLabel, errors);
2171
+ }
2172
+ if (typeof risk.severity === "string" && !severities.has(risk.severity)) {
2173
+ errors.push(`${riskLabel}.severity has unsupported value ${risk.severity}`);
2174
+ }
2175
+ }
2176
+ }
2177
+ }
2178
+
2179
+ if (mode === "multi-agent-coordination") {
2180
+ requireArray(result, "roles", label, errors);
2181
+ requireJsonArray(result, "reservations", label, errors);
2182
+ requireArray(result, "locking_rules", label, errors);
2183
+ requireString(result, "conflict_resolution", label, errors);
2184
+ if (Array.isArray(result.reservations)) {
2185
+ for (const [index, reservation] of result.reservations.entries()) {
2186
+ const reservationLabel = `${label}.reservations[${index}]`;
2187
+ for (const field of ["id", "owner_role", "scope", "evidence_path", "proposal_path"]) {
2188
+ requireString(reservation, field, reservationLabel, errors);
2189
+ }
2190
+ requireArray(reservation, "allowed_actions", reservationLabel, errors);
2191
+ }
2192
+ }
2193
+ }
2194
+
2195
+ if (mode === "source-boundary-contract") {
2196
+ requireJsonArray(result, "source_roles", label, errors);
2197
+ requireString(result, "promotion_rule", label, errors);
2198
+ requireArray(result, "rejected_promotion_targets", label, errors);
2199
+ const roles = new Set();
2200
+ if (Array.isArray(result.source_roles)) {
2201
+ for (const [index, role] of result.source_roles.entries()) {
2202
+ const roleLabel = `${label}.source_roles[${index}]`;
2203
+ requireString(role, "role", roleLabel, errors);
2204
+ requireString(role, "description", roleLabel, errors);
2205
+ if (typeof role.canonical_write_allowed !== "boolean") {
2206
+ errors.push(`${roleLabel}.canonical_write_allowed must be a boolean`);
2207
+ }
2208
+ if (typeof role.role === "string") {
2209
+ roles.add(role.role);
2210
+ }
2211
+ }
2212
+ }
2213
+ for (const requiredRole of ["canonical", "generated", "curated_human", "workflow", "local_scratch"]) {
2214
+ if (!roles.has(requiredRole)) {
2215
+ errors.push(`${label}.source_roles must include ${requiredRole}`);
2216
+ }
2217
+ }
2218
+ if (typeof result.promotion_rule === "string" && !result.promotion_rule.toLowerCase().includes("proposal")) {
2219
+ errors.push(`${label}.promotion_rule must require proposal-based promotion`);
2220
+ }
2221
+ }
2222
+
2223
+ return { errors, warnings, result };
2224
+ }
2225
+
2226
+ function validateProcessTransition(stateMachinePath, transitionRequestPath) {
2227
+ const errors = [];
2228
+ const warnings = [];
2229
+ const stateMachine = readJson(stateMachinePath);
2230
+ const request = readJson(transitionRequestPath);
2231
+ const label = "process_transition";
2232
+
2233
+ requireString(stateMachine, "schema_version", "state_machine", errors);
2234
+ requireString(stateMachine, "id", "state_machine", errors);
2235
+ requireString(stateMachine, "profile", "state_machine", errors);
2236
+ requireString(stateMachine, "public_safety", "state_machine", errors);
2237
+ requireArray(stateMachine, "states", "state_machine", errors);
2238
+ requireJsonArray(stateMachine, "transitions", "state_machine", errors);
2239
+ requireArray(stateMachine, "false_transition_guards", "state_machine", errors);
2240
+
2241
+ requireString(request, "schema_version", label, errors);
2242
+ requireString(request, "id", label, errors);
2243
+ requireString(request, "profile", label, errors);
2244
+ requireString(request, "public_safety", label, errors);
2245
+ requireString(request, "process_id", label, errors);
2246
+ requireString(request, "current_state", label, errors);
2247
+ requireString(request, "target_state", label, errors);
2248
+ requireArray(request, "evidence_refs", label, errors);
2249
+ for (const optionalStringField of ["launch_record_ref", "kaizen_review_ref", "no_reusable_lessons_reason"]) {
2250
+ if (typeof request[optionalStringField] !== "string") {
2251
+ errors.push(`${label}.${optionalStringField} must be a string`);
2252
+ }
2253
+ }
2254
+ requireArray(request, "limitations", label, errors);
2255
+
2256
+ if (stateMachine.profile !== undefined && stateMachine.profile !== "implementation_control") {
2257
+ errors.push("state_machine.profile must be implementation_control");
2258
+ }
2259
+ if (stateMachine.public_safety !== undefined && stateMachine.public_safety !== "synthetic_public") {
2260
+ errors.push("state_machine.public_safety must be synthetic_public");
2261
+ }
2262
+ if (request.profile !== undefined && request.profile !== "implementation_control") {
2263
+ errors.push(`${label}.profile must be implementation_control`);
2264
+ }
2265
+ if (request.public_safety !== undefined && request.public_safety !== "synthetic_public") {
2266
+ errors.push(`${label}.public_safety must be synthetic_public`);
2267
+ }
2268
+
2269
+ const states = new Set(Array.isArray(stateMachine.states) ? stateMachine.states : []);
2270
+ if (request.current_state && !states.has(request.current_state)) {
2271
+ errors.push(`${label}.current_state references unknown state ${request.current_state}`);
2272
+ }
2273
+ if (request.target_state && !states.has(request.target_state)) {
2274
+ errors.push(`${label}.target_state references unknown state ${request.target_state}`);
2275
+ }
2276
+
2277
+ const transitions = Array.isArray(stateMachine.transitions) ? stateMachine.transitions : [];
2278
+ const transition = transitions.find((item) => (
2279
+ item.from === request.current_state && item.to === request.target_state
2280
+ ));
2281
+ const requiredEvidence = transition && Array.isArray(transition.requires_evidence)
2282
+ ? transition.requires_evidence
2283
+ : [];
2284
+ const providedEvidence = Array.isArray(request.evidence_refs) ? request.evidence_refs : [];
2285
+ const missingEvidence = requiredEvidence.filter((requiredEvidenceRef) => (
2286
+ !providedEvidence.includes(requiredEvidenceRef)
2287
+ ));
2288
+ const terminalStates = new Set(Array.isArray(stateMachine.terminal_states) ? stateMachine.terminal_states : []);
2289
+ const terminalRequiresKaizen = transition && transition.terminal_requires_kaizen === true;
2290
+ const terminalTransition = terminalStates.has(request.target_state) || terminalRequiresKaizen === true;
2291
+ const launchRecordSatisfied = !(transition && transition.requires_launch_record === true) || Boolean(request.launch_record_ref);
2292
+ const kaizenSatisfied = !terminalTransition || Boolean(request.kaizen_review_ref) || Boolean(request.no_reusable_lessons_reason);
2293
+ const explanation = {
2294
+ process_id: typeof request.process_id === "string" ? request.process_id : "",
2295
+ current_state: typeof request.current_state === "string" ? request.current_state : "",
2296
+ target_state: typeof request.target_state === "string" ? request.target_state : "",
2297
+ matched_transition: Boolean(transition),
2298
+ matched_transition_ref: transition ? `${transition.from}->${transition.to}` : "",
2299
+ required_evidence: requiredEvidence,
2300
+ provided_evidence: providedEvidence,
2301
+ missing_evidence: missingEvidence,
2302
+ requires_launch_record: Boolean(transition && transition.requires_launch_record === true),
2303
+ launch_record_ref: typeof request.launch_record_ref === "string" ? request.launch_record_ref : "",
2304
+ launch_record_satisfied: launchRecordSatisfied,
2305
+ terminal_transition: terminalTransition,
2306
+ terminal_requires_kaizen: Boolean(terminalRequiresKaizen),
2307
+ kaizen_decision: {
2308
+ status: kaizenSatisfied ? (terminalTransition ? "satisfied" : "not_required") : "missing",
2309
+ kaizen_review_ref: typeof request.kaizen_review_ref === "string" ? request.kaizen_review_ref : "",
2310
+ no_reusable_lessons_reason: typeof request.no_reusable_lessons_reason === "string" ? request.no_reusable_lessons_reason : ""
2311
+ },
2312
+ false_transition_guard_summary: Array.isArray(stateMachine.false_transition_guards)
2313
+ ? stateMachine.false_transition_guards
2314
+ : []
2315
+ };
2316
+ if (!transition) {
2317
+ errors.push(`${label} transition ${request.current_state}->${request.target_state} is not allowed`);
2318
+ }
2319
+
2320
+ const evidence = new Set(Array.isArray(request.evidence_refs) ? request.evidence_refs : []);
2321
+ if (transition) {
2322
+ for (const requiredEvidenceRef of requiredEvidence) {
2323
+ if (!evidence.has(requiredEvidenceRef)) {
2324
+ errors.push(`${label} missing required evidence ${requiredEvidenceRef}`);
2325
+ }
2326
+ }
2327
+ }
2328
+
2329
+ if (transition && transition.requires_launch_record === true && !request.launch_record_ref) {
2330
+ errors.push(`${label} requires launch_record_ref for ${request.current_state}->${request.target_state}`);
2331
+ }
2332
+
2333
+ if ((terminalStates.has(request.target_state) || terminalRequiresKaizen) && !request.kaizen_review_ref && !request.no_reusable_lessons_reason) {
2334
+ errors.push(`${label} terminal transition requires kaizen_review_ref or no_reusable_lessons_reason`);
2335
+ }
2336
+
2337
+ const guardText = Array.isArray(stateMachine.false_transition_guards) ? stateMachine.false_transition_guards.join("\n").toLowerCase() : "";
2338
+ for (const requiredGuard of ["ready", "tests", "sync", "released", "terminal"]) {
2339
+ if (!guardText.includes(requiredGuard)) {
2340
+ warnings.push(`state_machine.false_transition_guards should mention ${requiredGuard}`);
2341
+ }
2342
+ }
2343
+
2344
+ return { errors, warnings, explanation };
2345
+ }
2346
+
2347
+ const rawArgs = process.argv.slice(2);
2348
+ const outputFormat = rawArgs.includes("--markdown") ? "markdown" : "json";
2349
+ const positionalArgs = rawArgs.filter((arg) => arg !== "--markdown" && arg !== "--json");
2350
+ const modeOrPackageDir = positionalArgs[0];
2351
+ if (!modeOrPackageDir) {
2352
+ usage();
2353
+ process.exit(2);
2354
+ }
2355
+
2356
+ try {
2357
+ const isSeedMode = modeOrPackageDir === "seed";
2358
+ const isProfileMode = modeOrPackageDir === "profile";
2359
+ const isContextPackMode = modeOrPackageDir === "context-pack";
2360
+ const isImplementationControlCycleMode = modeOrPackageDir === "implementation-control-cycle";
2361
+ const isProcessTransitionMode = modeOrPackageDir === "process-transition";
2362
+ const publicResultModes = new Set([
2363
+ "launch-record",
2364
+ "process-control-contract",
2365
+ "technology-quality-feedback",
2366
+ "character-layer-integration",
2367
+ "model-portability-evidence",
2368
+ "character-layer-readiness",
2369
+ "development-cockpit",
2370
+ "feature-implementation-traceability",
2371
+ "multi-source-quality-feedback",
2372
+ "graph-dna-alignment",
2373
+ "work-state-machine",
2374
+ "recovery-resume-record",
2375
+ "risk-control-matrix",
2376
+ "multi-agent-coordination",
2377
+ "source-boundary-contract"
2378
+ ]);
2379
+ const isPublicResultMode = publicResultModes.has(modeOrPackageDir);
2380
+ const targetPath = isSeedMode || isProfileMode || isContextPackMode || isImplementationControlCycleMode || isProcessTransitionMode || isPublicResultMode ? positionalArgs[1] : modeOrPackageDir;
2381
+ const contextPackPath = isContextPackMode ? positionalArgs[2] : null;
2382
+ const transitionRequestPath = isProcessTransitionMode ? positionalArgs[2] : null;
2383
+ if (!targetPath) {
2384
+ usage();
2385
+ process.exit(2);
2386
+ }
2387
+ if (isContextPackMode && !contextPackPath) {
2388
+ usage();
2389
+ process.exit(2);
2390
+ }
2391
+ if (isProcessTransitionMode && !transitionRequestPath) {
2392
+ usage();
2393
+ process.exit(2);
2394
+ }
2395
+ const result = isSeedMode
2396
+ ? validateSeed(path.resolve(targetPath))
2397
+ : isProfileMode
2398
+ ? validateProfile(path.resolve(targetPath))
2399
+ : isContextPackMode
2400
+ ? validateContextPack(path.resolve(targetPath), path.resolve(contextPackPath))
2401
+ : isImplementationControlCycleMode
2402
+ ? validateImplementationControlCycle(path.resolve(targetPath))
2403
+ : isProcessTransitionMode
2404
+ ? validateProcessTransition(path.resolve(targetPath), path.resolve(transitionRequestPath))
2405
+ : modeOrPackageDir === "character-layer-integration"
2406
+ ? validateCharacterLayerIntegration(path.resolve(targetPath))
2407
+ : modeOrPackageDir === "model-portability-evidence"
2408
+ ? validateModelPortabilityEvidence(path.resolve(targetPath))
2409
+ : modeOrPackageDir === "character-layer-readiness"
2410
+ ? validateCharacterLayerReadiness(path.resolve(targetPath))
2411
+ : isPublicResultMode
2412
+ ? validatePublicImplementationControlResult(path.resolve(targetPath), modeOrPackageDir)
2413
+ : validatePackage(path.resolve(targetPath));
2414
+ const output = {
2415
+ mode: isSeedMode ? "seed" : isProfileMode ? "profile" : isContextPackMode ? "context_pack" : isImplementationControlCycleMode ? "implementation_control_cycle" : isProcessTransitionMode ? "process_transition" : isPublicResultMode ? modeOrPackageDir.replace(/-/g, "_") : "package",
2416
+ target: isContextPackMode ? path.resolve(contextPackPath) : isProcessTransitionMode ? path.resolve(transitionRequestPath) : path.resolve(targetPath),
2417
+ package: isContextPackMode ? path.resolve(targetPath) : undefined,
2418
+ state_machine: isProcessTransitionMode ? path.resolve(targetPath) : undefined,
2419
+ valid: result.errors.length === 0,
2420
+ errors: result.errors,
2421
+ warnings: result.warnings,
2422
+ explanation: result.explanation,
2423
+ result: isPublicResultMode ? result.result : undefined
2424
+ };
2425
+ if (outputFormat === "markdown") {
2426
+ console.log(formatMarkdownReport(output));
2427
+ } else {
2428
+ console.log(JSON.stringify(output, null, 2));
2429
+ }
2430
+ process.exit(output.valid ? 0 : 1);
2431
+ } catch (error) {
2432
+ console.error(error.message);
2433
+ process.exit(1);
2434
+ }