@nimiplatform/nimi-coding 0.2.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/CHANGELOG.md +8 -80
  2. package/CONTRIBUTING.md +5 -34
  3. package/README.md +47 -350
  4. package/README.zh-CN.md +33 -287
  5. package/cli/commands/start.mjs +48 -688
  6. package/cli/commands/validate-spec-audit.mjs +1 -5
  7. package/cli/constants.mjs +9 -417
  8. package/cli/dev/run-cli-smoke.mjs +24 -0
  9. package/cli/dev/run-suite.mjs +17 -0
  10. package/cli/help.mjs +28 -145
  11. package/cli/index.mjs +5 -33
  12. package/cli/lib/blueprint-audit.mjs +5 -12
  13. package/cli/lib/bootstrap.mjs +0 -9
  14. package/cli/lib/contracts.mjs +0 -163
  15. package/cli/lib/doctor.mjs +155 -10
  16. package/cli/lib/entrypoints.mjs +63 -167
  17. package/cli/lib/internal/contracts-loaders.mjs +0 -85
  18. package/cli/lib/internal/contracts-parse.mjs +84 -520
  19. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +13 -8
  20. package/cli/lib/internal/surface-taxonomy-validators.mjs +316 -66
  21. package/cli/lib/internal/validators-shared.mjs +0 -16
  22. package/cli/lib/internal/validators-spec-helpers.mjs +7 -140
  23. package/cli/lib/internal/validators-spec.mjs +103 -342
  24. package/cli/lib/shared.mjs +1 -42
  25. package/cli/lib/validators.mjs +0 -48
  26. package/cli/seeds/seed-policy.yaml +0 -3
  27. package/config/bootstrap.yaml +4 -4
  28. package/config/spec-generation-inputs.yaml +6 -12
  29. package/contracts/domain-admission.schema.yaml +3 -3
  30. package/contracts/migration-inventory.schema.yaml +12 -75
  31. package/contracts/negative-fixtures.yaml +19 -99
  32. package/contracts/placement-contract.schema.yaml +49 -78
  33. package/contracts/projection-edge.schema.yaml +37 -121
  34. package/contracts/shared-enums.yaml +4 -8
  35. package/contracts/spec-generation-inputs.schema.yaml +15 -112
  36. package/contracts/spec-layout.schema.yaml +32 -0
  37. package/contracts/surface-taxonomy.schema.yaml +43 -94
  38. package/contracts/table-family.schema.yaml +1 -1
  39. package/contracts/tracked-output-admission.schema.yaml +13 -66
  40. package/methodology/core.yaml +33 -25
  41. package/methodology/four-closure-policy.yaml +18 -26
  42. package/methodology/role-separation-policy.yaml +21 -27
  43. package/methodology/spec-reconstruction.yaml +17 -34
  44. package/package.json +4 -6
  45. package/spec/_meta/spec-tree-model.yaml +5 -101
  46. package/spec/product-scope.yaml +25 -57
  47. package/adapters/README.md +0 -25
  48. package/adapters/claude/README.md +0 -89
  49. package/adapters/claude/profile.yaml +0 -70
  50. package/adapters/codex/README.md +0 -53
  51. package/adapters/codex/profile.yaml +0 -78
  52. package/adapters/oh-my-codex/README.md +0 -184
  53. package/adapters/oh-my-codex/profile.yaml +0 -46
  54. package/cli/commands/admit-high-risk-decision.mjs +0 -108
  55. package/cli/commands/audit-sweep.mjs +0 -364
  56. package/cli/commands/closeout.mjs +0 -186
  57. package/cli/commands/decide-high-risk-execution.mjs +0 -124
  58. package/cli/commands/handoff.mjs +0 -123
  59. package/cli/commands/ingest-high-risk-execution.mjs +0 -95
  60. package/cli/commands/review-high-risk-execution.mjs +0 -95
  61. package/cli/commands/sweep-design.mjs +0 -295
  62. package/cli/commands/sweep.mjs +0 -22
  63. package/cli/commands/topic-formatters.mjs +0 -382
  64. package/cli/commands/topic-goal.mjs +0 -33
  65. package/cli/commands/topic-options-shared.mjs +0 -27
  66. package/cli/commands/topic-options-workflow.mjs +0 -767
  67. package/cli/commands/topic-options.mjs +0 -626
  68. package/cli/commands/topic-runner.mjs +0 -169
  69. package/cli/commands/topic.mjs +0 -795
  70. package/cli/commands/validate-acceptance.mjs +0 -5
  71. package/cli/commands/validate-execution-packet.mjs +0 -5
  72. package/cli/commands/validate-orchestration-state.mjs +0 -5
  73. package/cli/commands/validate-prompt.mjs +0 -5
  74. package/cli/commands/validate-worker-output.mjs +0 -5
  75. package/cli/lib/adapter-profiles.mjs +0 -403
  76. package/cli/lib/audit-execution.mjs +0 -52
  77. package/cli/lib/audit-sweep-runtime/admissions.mjs +0 -508
  78. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +0 -356
  79. package/cli/lib/audit-sweep-runtime/chunks.mjs +0 -697
  80. package/cli/lib/audit-sweep-runtime/claude-auditor.mjs +0 -647
  81. package/cli/lib/audit-sweep-runtime/closeout.mjs +0 -144
  82. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +0 -654
  83. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +0 -516
  84. package/cli/lib/audit-sweep-runtime/common.mjs +0 -341
  85. package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +0 -172
  86. package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +0 -155
  87. package/cli/lib/audit-sweep-runtime/format.mjs +0 -57
  88. package/cli/lib/audit-sweep-runtime/ingest.mjs +0 -486
  89. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +0 -425
  90. package/cli/lib/audit-sweep-runtime/inventory.mjs +0 -798
  91. package/cli/lib/audit-sweep-runtime/ledger.mjs +0 -315
  92. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +0 -101
  93. package/cli/lib/audit-sweep-runtime/remediation.mjs +0 -349
  94. package/cli/lib/audit-sweep-runtime/rerun.mjs +0 -129
  95. package/cli/lib/audit-sweep-runtime/risk-budget.mjs +0 -300
  96. package/cli/lib/audit-sweep-runtime/status.mjs +0 -62
  97. package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +0 -215
  98. package/cli/lib/audit-sweep-runtime/validators.mjs +0 -797
  99. package/cli/lib/audit-sweep.mjs +0 -19
  100. package/cli/lib/authority-convergence.mjs +0 -704
  101. package/cli/lib/closeout.mjs +0 -732
  102. package/cli/lib/codex-sdk-runner.mjs +0 -76
  103. package/cli/lib/external-execution.mjs +0 -101
  104. package/cli/lib/handoff.mjs +0 -812
  105. package/cli/lib/high-risk-admission.mjs +0 -512
  106. package/cli/lib/high-risk-decision.mjs +0 -353
  107. package/cli/lib/high-risk-ingest.mjs +0 -321
  108. package/cli/lib/high-risk-review.mjs +0 -267
  109. package/cli/lib/internal/contracts-parse-high-risk.mjs +0 -131
  110. package/cli/lib/internal/contracts-validators.mjs +0 -399
  111. package/cli/lib/internal/doctor-bootstrap-surface.mjs +0 -406
  112. package/cli/lib/internal/doctor-delegated-surface.mjs +0 -256
  113. package/cli/lib/internal/doctor-finalize.mjs +0 -383
  114. package/cli/lib/internal/doctor-format.mjs +0 -286
  115. package/cli/lib/internal/doctor-inspectors.mjs +0 -327
  116. package/cli/lib/internal/doctor-state.mjs +0 -205
  117. package/cli/lib/internal/validators-artifacts.mjs +0 -515
  118. package/cli/lib/sweep-design-runtime/common.mjs +0 -246
  119. package/cli/lib/sweep-design-runtime/engine.mjs +0 -733
  120. package/cli/lib/sweep-design-runtime/fix-topic.mjs +0 -414
  121. package/cli/lib/sweep-design-runtime/lifecycle.mjs +0 -54
  122. package/cli/lib/sweep-design-runtime/results.mjs +0 -324
  123. package/cli/lib/sweep-design.mjs +0 -8
  124. package/cli/lib/topic-artifacts.mjs +0 -186
  125. package/cli/lib/topic-authority-coverage.mjs +0 -73
  126. package/cli/lib/topic-closeout.mjs +0 -560
  127. package/cli/lib/topic-common.mjs +0 -404
  128. package/cli/lib/topic-decisions.mjs +0 -332
  129. package/cli/lib/topic-draft-packets.mjs +0 -167
  130. package/cli/lib/topic-execution.mjs +0 -515
  131. package/cli/lib/topic-goal.mjs +0 -440
  132. package/cli/lib/topic-ledger.mjs +0 -281
  133. package/cli/lib/topic-lifecycle-artifacts.mjs +0 -173
  134. package/cli/lib/topic-root-validation.mjs +0 -288
  135. package/cli/lib/topic-runner-commands.mjs +0 -174
  136. package/cli/lib/topic-runner-deferral.mjs +0 -532
  137. package/cli/lib/topic-runner-stale-gates.mjs +0 -114
  138. package/cli/lib/topic-runner-validation.mjs +0 -138
  139. package/cli/lib/topic-runner.mjs +0 -727
  140. package/cli/lib/topic-scaffold.mjs +0 -252
  141. package/cli/lib/topic-waves.mjs +0 -403
  142. package/cli/lib/topic.mjs +0 -81
  143. package/config/audit-execution-artifacts.yaml +0 -20
  144. package/config/external-execution-artifacts.yaml +0 -16
  145. package/config/host-adapter.yaml +0 -30
  146. package/config/host-profile.yaml +0 -29
  147. package/config/installer-evidence.yaml +0 -31
  148. package/config/skill-installer.yaml +0 -23
  149. package/config/skill-manifest.yaml +0 -48
  150. package/config/skills.yaml +0 -30
  151. package/contracts/acceptance.schema.yaml +0 -16
  152. package/contracts/admission-checklist.schema.yaml +0 -15
  153. package/contracts/audit-chunk.schema.yaml +0 -123
  154. package/contracts/audit-closeout.schema.yaml +0 -51
  155. package/contracts/audit-finding.schema.yaml +0 -61
  156. package/contracts/audit-ledger.schema.yaml +0 -138
  157. package/contracts/audit-plan.schema.yaml +0 -138
  158. package/contracts/audit-remediation-map.schema.yaml +0 -52
  159. package/contracts/audit-rerun.schema.yaml +0 -31
  160. package/contracts/audit-sweep-result.yaml +0 -53
  161. package/contracts/authority-convergence-audit.schema.yaml +0 -19
  162. package/contracts/closeout.schema.yaml +0 -25
  163. package/contracts/decision-review.schema.yaml +0 -16
  164. package/contracts/doc-spec-audit-result.yaml +0 -19
  165. package/contracts/execution-packet.schema.yaml +0 -49
  166. package/contracts/external-host-compatibility.yaml +0 -22
  167. package/contracts/forbidden-shortcuts.catalog.yaml +0 -23
  168. package/contracts/high-risk-admission.schema.yaml +0 -23
  169. package/contracts/high-risk-execution-result.yaml +0 -20
  170. package/contracts/orchestration-state.schema.yaml +0 -41
  171. package/contracts/overflow-continuation.schema.yaml +0 -12
  172. package/contracts/packet.schema.yaml +0 -30
  173. package/contracts/pending-note.schema.yaml +0 -17
  174. package/contracts/prompt.schema.yaml +0 -12
  175. package/contracts/remediation.schema.yaml +0 -16
  176. package/contracts/result.schema.yaml +0 -24
  177. package/contracts/spec-reconstruction-result.yaml +0 -41
  178. package/contracts/sweep-design-result.yaml +0 -349
  179. package/contracts/topic-goal.schema.yaml +0 -87
  180. package/contracts/topic-run-ledger.schema.yaml +0 -72
  181. package/contracts/topic-step-decision.schema.yaml +0 -45
  182. package/contracts/topic.schema.yaml +0 -65
  183. package/contracts/true-close.schema.yaml +0 -15
  184. package/contracts/wave.schema.yaml +0 -29
  185. package/contracts/worker-output.schema.yaml +0 -15
  186. package/contracts/workflow-consumer.schema.yaml +0 -110
  187. package/methodology/audit-sweep-p0p1-recall.yaml +0 -45
  188. package/methodology/authority-convergence-policy.yaml +0 -42
  189. package/methodology/overflow-continuation-policy.yaml +0 -14
  190. package/methodology/skill-exchange-projection.yaml +0 -114
  191. package/methodology/skill-handoff.yaml +0 -34
  192. package/methodology/skill-installer-result.yaml +0 -27
  193. package/methodology/skill-installer-summary-projection.yaml +0 -181
  194. package/methodology/skill-runtime.yaml +0 -23
  195. package/methodology/spec-target-truth-profile.yaml +0 -46
  196. package/methodology/topic-lifecycle-report.yaml +0 -144
  197. package/methodology/topic-lifecycle.yaml +0 -37
  198. package/methodology/topic-naming-ontology.yaml +0 -21
  199. package/methodology/topic-ontology.yaml +0 -38
  200. package/methodology/topic-validation-policy.yaml +0 -9
  201. package/methodology/wave-dag-policy.yaml +0 -14
  202. package/spec/_meta/command-gating-matrix.yaml +0 -143
  203. package/spec/_meta/generate-drift-migration-checklist.yaml +0 -137
  204. package/spec/_meta/governance-routing-cutover-checklist.yaml +0 -35
  205. package/spec/_meta/phase2-impacted-surface-matrix.yaml +0 -44
  206. package/spec/_meta/spec-authority-cutover-readiness.yaml +0 -102
  207. package/spec/bootstrap-state.yaml +0 -99
@@ -1,284 +1,73 @@
1
1
  import {
2
- BLUEPRINT_REFERENCE_REF,
3
- SPEC_GENERATION_AUDIT_CONTRACT_REF,
4
2
  SPEC_GENERATION_AUDIT_COVERAGE_STATUS_ENUM,
5
- SPEC_GENERATION_AUDIT_FILE_REQUIRED_FIELDS,
6
- SPEC_GENERATION_AUDIT_REF,
7
3
  SPEC_GENERATION_AUDIT_REQUIRED_TOP_LEVEL_FIELDS,
8
4
  SPEC_GENERATION_AUDIT_SOURCE_BASIS_ENUM,
9
- SPEC_GENERATION_INPUTS_CONTRACT_REF,
10
- SPEC_GENERATION_INPUTS_REF,
11
- SPEC_RECONSTRUCTION_SUMMARY_REQUIRED_FIELDS,
12
- SPEC_RECONSTRUCTION_SUMMARY_STATUS,
13
- SPEC_TREE_MODEL_REF,
14
5
  } from "../../constants.mjs";
15
- import {
16
- arraysEqual,
17
- isPlainObject,
18
- toStringArray,
19
- } from "../value-helpers.mjs";
6
+ import { arraysEqual, isPlainObject, toStringArray } from "../value-helpers.mjs";
20
7
  import { parseYamlText } from "../yaml-helpers.mjs";
21
- export {
22
- parseAuditSweepContract,
23
- parseDocSpecAuditContract,
24
- parseExternalHostCompatibilityContract,
25
- parseHighRiskAdmissionContract,
26
- parseHighRiskExecutionContract,
27
- parseHighRiskSchemaContract,
28
- } from "./contracts-parse-high-risk.mjs";
29
8
 
30
- const SPEC_TREE_PROFILE_ENUM = ["minimal", "standard", "mature", "surface_taxonomy_v1"];
31
- const AUTHORITY_MODE_ENUM = [
32
- "external_authority_active",
33
- "external_blueprint_active",
34
- "canonical_cutover_ready",
35
- "canonical_active",
36
- "surface_class_validated",
37
- ];
38
- const BLUEPRINT_MODE_ENUM = [
39
- "none",
40
- "repo_spec_blueprint",
41
- "custom_blueprint",
42
- ];
43
- const SPEC_GENERATION_MODE_ENUM = ["mixed", "class_filtered"];
44
- const SPEC_GENERATION_ACCEPTANCE_MODE_ENUM = [
45
- "canonical_tree_validity_without_blueprint",
9
+ const ACCEPTANCE_MODES = [
46
10
  "semantic_and_structural_parity_when_blueprint_exists",
47
11
  "placement_validity_before_generation",
48
12
  ];
49
- const SPEC_GENERATION_ORDER_ENUM = [
50
- "index",
51
- "kernel_markdown",
52
- "kernel_tables",
53
- "generated_views",
54
- "thin_guides",
55
- "classify_inputs",
56
- "validate_placement",
57
- "product_authority",
58
- "product_authority_tables",
59
- "derived_views",
60
- "generation_audit",
13
+ const SPEC_GENERATION_INPUT_FIELDS = [
14
+ "mode",
15
+ "canonical_target_root",
16
+ "code_inputs",
17
+ "docs_inputs",
18
+ "structure_inputs",
19
+ "local_inputs",
20
+ "forbidden_source_classes",
21
+ "generation_order",
22
+ "inference_rules",
23
+ "acceptance_mode",
24
+ ];
25
+ const SPEC_GENERATION_INPUT_DOCUMENT_FIELDS = [
26
+ "version",
27
+ "contract_ref",
28
+ "spec_generation_inputs",
61
29
  ];
62
- const TOPIC_LIFECYCLE_REPORT_MARKDOWN = /^\.nimi\/topics\/(?:proposal|ongoing|pending|closed)\/\d{4}-\d{2}-\d{2}-[a-z0-9]+(?:-[a-z0-9]+)*\/[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*\.md$/;
63
-
64
- function normalizeAuthorityModeValue(value) {
65
- return value === "external_blueprint_active" ? "external_authority_active" : value;
66
- }
67
30
 
68
31
  function toStringOrNull(value) {
69
32
  return typeof value === "string" ? value : null;
70
33
  }
71
34
 
72
- function toStringList(value) {
73
- if (typeof value === "string") {
74
- return [value];
75
- }
76
- return toStringArray(value);
35
+ function hasExactFields(value, expectedFields) {
36
+ return isPlainObject(value)
37
+ && arraysEqual(Object.keys(value).sort(), [...expectedFields].sort());
77
38
  }
78
39
 
79
- function normalizePathClass(entry) {
80
- if (!isPlainObject(entry)) {
81
- return null;
82
- }
83
-
84
- return {
85
- id: toStringOrNull(entry.id),
86
- pathPatterns: toStringArray(entry.path_patterns),
87
- excludedPathPatterns: toStringArray(entry.excluded_path_patterns),
88
- allowedExtensions: toStringArray(entry.allowed_extensions),
89
- generatorRefs: toStringArray(entry.generator_refs),
90
- mustReferenceNormativeIds: entry.must_reference_normative_ids === true,
91
- normative: entry.normative === true,
92
- };
93
- }
94
-
95
- function normalizeSpecDomain(entry) {
96
- if (!isPlainObject(entry)) {
97
- return null;
98
- }
99
-
100
- return {
101
- id: toStringOrNull(entry.id),
102
- root: toStringOrNull(entry.root),
103
- normativeRoot: toStringOrNull(entry.normative_root),
104
- tablesRoot: toStringOrNull(entry.tables_root),
105
- generatedRoot: toStringOrNull(entry.generated_root),
106
- guidePaths: toStringArray(entry.guide_paths),
107
- };
108
- }
109
-
110
- function normalizeGeneratedPipeline(entry) {
111
- if (!isPlainObject(entry)) {
112
- return null;
113
- }
114
-
115
- return {
116
- id: toStringOrNull(entry.id),
117
- ownerSurface: toStringOrNull(entry.owner_surface),
118
- inputRoots: toStringArray(entry.input_roots).length > 0
119
- ? toStringArray(entry.input_roots)
120
- : [
121
- ...toStringList(entry.input_contract_ref),
122
- ...toStringList(entry.input_config_ref),
123
- ],
124
- outputRoots: toStringArray(entry.output_roots),
125
- generateCommand: toStringOrNull(entry.generate_command),
126
- driftCheckCommand: toStringOrNull(entry.drift_check_command),
127
- };
128
- }
129
-
130
- function normalizeV2SpecDomain(entry) {
131
- if (!isPlainObject(entry)) {
132
- return null;
133
- }
134
- const root = toStringOrNull(entry.root);
135
- return {
136
- id: toStringOrNull(entry.id),
137
- root,
138
- normativeRoot: root ? `${root}/kernel` : null,
139
- tablesRoot: root ? `${root}/kernel/tables` : null,
140
- generatedRoot: null,
141
- guidePaths: [],
142
- };
143
- }
144
-
145
- function normalizeV2PathClass(entry) {
146
- if (!isPlainObject(entry)) {
147
- return null;
148
- }
149
- return {
150
- id: toStringOrNull(entry.id),
151
- pathPatterns: toStringArray(entry.path_patterns),
152
- excludedPathPatterns: toStringArray(entry.excluded_path_patterns),
153
- allowedExtensions: toStringArray(entry.allowed_extensions),
154
- generatorRefs: [],
155
- mustReferenceNormativeIds: entry.must_reference_product_authority_ids === true,
156
- normative: ["product_authority", "product_authority_table"].includes(entry.id),
157
- };
158
- }
159
-
160
- function pathStartsWithRoot(targetPath, root) {
161
- if (typeof targetPath !== "string" || typeof root !== "string") {
162
- return false;
163
- }
164
-
165
- return targetPath === root || targetPath.startsWith(`${root}/`);
166
- }
167
-
168
- function isDatePrefixedTopicLifecycleMarkdownPath(value) {
169
- if (typeof value !== "string") {
170
- return false;
171
- }
172
- return TOPIC_LIFECYCLE_REPORT_MARKDOWN.test(value);
173
- }
174
-
175
- function topicLifecycleMarkdownPathsAreSortable(paths) {
176
- return paths.every((entry) => {
177
- if (typeof entry !== "string") {
178
- return true;
179
- }
180
- if (entry.startsWith(".local/report/")) {
181
- return false;
182
- }
183
- if (!entry.startsWith(".nimi/topics/")) {
184
- return true;
185
- }
186
- if (!entry.endsWith(".md")) {
187
- return true;
188
- }
189
- return isDatePrefixedTopicLifecycleMarkdownPath(entry);
190
- });
191
- }
192
-
193
- function isAllowedV2AuthorityDocsRoot(root) {
194
- if (typeof root !== "string" || root.length === 0) {
195
- return false;
196
- }
197
- if (root === "." || root === "./" || root === "/" || root === "**" || root.includes("..")) {
198
- return false;
199
- }
200
- return root === ".nimi/spec" || root.startsWith(".nimi/spec/");
201
- }
202
-
203
- export function parseSpecReconstructionContract(text) {
204
- const parsed = parseYamlText(text);
205
- const version = parsed?.version ?? null;
206
- const summaryRequiredFields = toStringArray(parsed?.summary_required_fields);
207
- const summaryStatusEnum = toStringArray(parsed?.summary_status_enum);
208
- const completionRequirements = toStringArray(parsed?.completion_requirements);
209
- const canonicalTreeCompletion = isPlainObject(parsed?.canonical_tree_completion)
210
- ? {
211
- profileRef: toStringOrNull(parsed.canonical_tree_completion.profile_ref),
212
- generationInputsRef: toStringOrNull(parsed.canonical_tree_completion.generation_inputs_ref),
213
- auditContractRef: toStringOrNull(parsed.canonical_tree_completion.audit_contract_ref),
214
- auditRef: toStringOrNull(parsed.canonical_tree_completion.audit_ref),
215
- requiredTreeState: toStringOrNull(parsed.canonical_tree_completion.required_tree_state),
216
- requiredFilesValid: parsed.canonical_tree_completion.required_files_valid === true,
217
- }
218
- : null;
219
-
220
- const expectedSummaryFields = version === 2
221
- ? [...SPEC_RECONSTRUCTION_SUMMARY_REQUIRED_FIELDS.slice(0, 2), "placement_report_ref", ...SPEC_RECONSTRUCTION_SUMMARY_REQUIRED_FIELDS.slice(2)]
222
- : SPEC_RECONSTRUCTION_SUMMARY_REQUIRED_FIELDS;
223
- const expectedProfileRef = version === 2 ? ".nimi/contracts/surface-taxonomy.schema.yaml" : SPEC_TREE_MODEL_REF;
224
- const expectedInputsRef = version === 2 ? ".nimi/config/spec-generation-inputs.yaml" : SPEC_GENERATION_INPUTS_REF;
225
- const expectedAuditContractRef = version === 2 ? ".nimi/contracts/spec-generation-audit.schema.yaml" : SPEC_GENERATION_AUDIT_CONTRACT_REF;
226
- const expectedAuditRef = version === 2 ? ".nimi/local/state/spec-generation/spec-generation-audit.yaml" : SPEC_GENERATION_AUDIT_REF;
227
- const fileClassRequirement = version === 2
228
- ? "declared_surface_class_constraints_valid"
229
- : "declared_file_class_constraints_valid";
230
- const auditRequirement = version === 2
231
- ? "spec_generation_audit_present_and_valid_as_local_state"
232
- : "spec_generation_audit_present_and_valid";
233
-
234
- return {
235
- ok: [1, 2].includes(version)
236
- && arraysEqual(summaryRequiredFields, expectedSummaryFields)
237
- && arraysEqual(summaryStatusEnum, SPEC_RECONSTRUCTION_SUMMARY_STATUS)
238
- && completionRequirements.includes("canonical_tree_ready")
239
- && completionRequirements.includes("declared_profile_required_files_valid")
240
- && completionRequirements.includes(fileClassRequirement)
241
- && completionRequirements.includes(auditRequirement)
242
- && completionRequirements.includes("required_canonical_files_have_matching_audit_entries")
243
- && completionRequirements.includes("unresolved_gaps_must_remain_explicit")
244
- && completionRequirements.includes("semantic_and_structural_parity_when_blueprint_exists")
245
- && canonicalTreeCompletion?.profileRef === expectedProfileRef
246
- && canonicalTreeCompletion?.generationInputsRef === expectedInputsRef
247
- && canonicalTreeCompletion?.auditContractRef === expectedAuditContractRef
248
- && canonicalTreeCompletion?.auditRef === expectedAuditRef
249
- && canonicalTreeCompletion?.requiredTreeState === "canonical_tree_ready"
250
- && canonicalTreeCompletion?.requiredFilesValid === true,
251
- canonicalTreeCompletion,
252
- summaryRequiredFields,
253
- summaryStatusEnum,
254
- completionRequirements,
255
- };
40
+ function isAllowedAuthorityRoot(root) {
41
+ return typeof root === "string"
42
+ && (root === ".nimi/spec" || root.startsWith(".nimi/spec/"))
43
+ && !root.includes("..");
256
44
  }
257
45
 
258
46
  export function parseSpecGenerationAuditContract(text) {
259
47
  const parsed = parseYamlText(text);
260
- const version = parsed?.version ?? null;
261
48
  const requiredTopLevelFields = toStringArray(parsed?.required_top_level_fields);
262
49
  const requiredFileEntryFields = toStringArray(parsed?.required_file_entry_fields);
263
50
  const sourceBasisEnum = toStringArray(parsed?.source_basis_enum);
264
51
  const coverageStatusEnum = toStringArray(parsed?.coverage_status_enum);
265
52
  const hardConstraints = toStringArray(parsed?.hard_constraints);
266
-
267
- const expectedTopLevelFields = version === 2
268
- ? [...SPEC_GENERATION_AUDIT_REQUIRED_TOP_LEVEL_FIELDS.slice(0, 4), "placement_report_ref", ...SPEC_GENERATION_AUDIT_REQUIRED_TOP_LEVEL_FIELDS.slice(4)]
269
- : SPEC_GENERATION_AUDIT_REQUIRED_TOP_LEVEL_FIELDS;
270
- const expectedFileEntryFields = version === 2
271
- ? ["canonical_path", "surface_class", "source_refs", "source_basis", "coverage_status", "unresolved_items"]
272
- : SPEC_GENERATION_AUDIT_FILE_REQUIRED_FIELDS;
273
- const expectedTargetRef = version === 2 ? ".nimi/local/state/spec-generation/spec-generation-audit.yaml" : SPEC_GENERATION_AUDIT_REF;
274
- const sourceConstraint = version === 2
275
- ? "source_refs_must_stay_within_class_filtered_declared_inputs"
276
- : "source_refs_must_stay_within_declared_inputs_or_optional_benchmark_root";
53
+ const expectedTopLevelFields = [
54
+ ...SPEC_GENERATION_AUDIT_REQUIRED_TOP_LEVEL_FIELDS.slice(0, 4),
55
+ "placement_report_ref",
56
+ ...SPEC_GENERATION_AUDIT_REQUIRED_TOP_LEVEL_FIELDS.slice(4),
57
+ ];
58
+ const expectedFileEntryFields = [
59
+ "canonical_path",
60
+ "surface_class",
61
+ "source_refs",
62
+ "source_basis",
63
+ "coverage_status",
64
+ "unresolved_items",
65
+ ];
277
66
 
278
67
  return {
279
- ok: [1, 2].includes(version)
68
+ ok: parsed?.version === 2
280
69
  && String(parsed?.audit_contract?.id ?? "") === "canonical_spec_generation_audit"
281
- && String(parsed?.audit_contract?.target_ref ?? "") === expectedTargetRef
70
+ && String(parsed?.audit_contract?.target_ref ?? "") === ".nimi/local/state/spec-generation/spec-generation-audit.yaml"
282
71
  && arraysEqual(requiredTopLevelFields, expectedTopLevelFields)
283
72
  && arraysEqual(requiredFileEntryFields, expectedFileEntryFields)
284
73
  && arraysEqual(sourceBasisEnum, SPEC_GENERATION_AUDIT_SOURCE_BASIS_ENUM)
@@ -286,7 +75,7 @@ export function parseSpecGenerationAuditContract(text) {
286
75
  && hardConstraints.includes("every_generated_canonical_file_requires_a_matching_audit_entry")
287
76
  && hardConstraints.includes("required_canonical_files_must_not_be_placeholder_not_allowed")
288
77
  && hardConstraints.includes("unresolved_or_inferred_content_must_be_explicit")
289
- && hardConstraints.includes(sourceConstraint)
78
+ && hardConstraints.includes("source_refs_must_stay_within_class_filtered_declared_inputs")
290
79
  && hardConstraints.includes("no_empty_success_looking_audit_entries"),
291
80
  requiredTopLevelFields,
292
81
  requiredFileEntryFields,
@@ -303,39 +92,16 @@ export function parseSpecGenerationInputsContract(text) {
303
92
  const generationOrderEnum = toStringArray(parsed?.generation_order_enum);
304
93
  const hardConstraints = toStringArray(parsed?.hard_constraints);
305
94
 
306
- if (parsed?.version === 2) {
307
- return {
308
- ok: String(contract?.id ?? "") === "canonical_spec_generation_inputs"
309
- && String(contract?.owner ?? "") === "nimi-coding"
310
- && requiredFields.includes("mode")
311
- && requiredFields.includes("canonical_target_root")
312
- && requiredFields.includes("docs_inputs")
313
- && requiredFields.includes("forbidden_source_classes")
314
- && arraysEqual(toStringArray(parsed?.mode_enum), ["class_filtered"])
315
- && SPEC_GENERATION_ACCEPTANCE_MODE_ENUM.includes(toStringArray(parsed?.acceptance_mode_enum)[0])
316
- && generationOrderEnum.includes("classify_inputs")
317
- && generationOrderEnum.includes("validate_placement")
318
- && hardConstraints.includes("docs_roots_blanket_ingestion_is_forbidden")
319
- && hardConstraints.includes("each_input_file_must_have_an_accepted_surface_class_before_render"),
320
- requiredFields,
321
- generationOrderEnum,
322
- hardConstraints,
323
- };
324
- }
325
-
326
95
  return {
327
- ok: parsed?.version === 1
96
+ ok: parsed?.version === 3
328
97
  && String(contract?.id ?? "") === "canonical_spec_generation_inputs"
329
- && String(contract?.target_root ?? "") === ".nimi/spec"
330
- && arraysEqual(toStringArray(contract?.mode_enum), SPEC_GENERATION_MODE_ENUM)
331
- && arraysEqual(toStringArray(contract?.acceptance_mode_enum), SPEC_GENERATION_ACCEPTANCE_MODE_ENUM)
332
- && arraysEqual(generationOrderEnum, SPEC_GENERATION_ORDER_ENUM)
333
- && requiredFields.includes("mode")
334
- && requiredFields.includes("canonical_target_root")
335
- && requiredFields.includes("benchmark_blueprint_root")
336
- && hardConstraints.includes("canonical_target_root_must_be_.nimi/spec")
337
- && hardConstraints.includes("local_report_markdown_paths_must_use_topic_lifecycle_shape")
338
- && hardConstraints.includes("human_authored_topic_reports_must_use_.nimi/topics_as_canonical_root"),
98
+ && String(contract?.owner ?? "") === "nimi-coding"
99
+ && arraysEqual(toStringArray(parsed?.mode_enum), ["class_filtered"])
100
+ && arraysEqual(requiredFields, SPEC_GENERATION_INPUT_FIELDS)
101
+ && generationOrderEnum.includes("classify_inputs")
102
+ && generationOrderEnum.includes("validate_placement")
103
+ && hardConstraints.includes("docs_roots_blanket_ingestion_is_forbidden")
104
+ && hardConstraints.includes("each_input_file_must_have_an_accepted_surface_class_before_render"),
339
105
  requiredFields,
340
106
  generationOrderEnum,
341
107
  hardConstraints,
@@ -345,236 +111,51 @@ export function parseSpecGenerationInputsContract(text) {
345
111
  export function parseSpecGenerationInputsConfig(text) {
346
112
  const parsed = parseYamlText(text);
347
113
  const config = parsed?.spec_generation_inputs;
348
- const mode = toStringOrNull(config?.mode);
349
- const canonicalTargetRoot = toStringOrNull(config?.canonical_target_root);
350
- const codeRoots = toStringArray(config?.code_roots);
351
- const docsRoots = toStringArray(config?.docs_roots);
352
- const structureRoots = toStringArray(config?.structure_roots);
353
114
  const codeInputs = Array.isArray(config?.code_inputs) ? config.code_inputs : [];
354
115
  const docsInputs = Array.isArray(config?.docs_inputs) ? config.docs_inputs : [];
355
116
  const structureInputs = Array.isArray(config?.structure_inputs) ? config.structure_inputs : [];
356
- const topicInputs = Array.isArray(config?.topic_inputs) ? config.topic_inputs : [];
357
117
  const localInputs = Array.isArray(config?.local_inputs) ? config.local_inputs : [];
358
118
  const forbiddenSourceClasses = toStringArray(config?.forbidden_source_classes);
359
- const humanNotePaths = toStringArray(config?.human_note_paths);
360
- const benchmarkBlueprintRoot = typeof config?.benchmark_blueprint_root === "string"
361
- ? config.benchmark_blueprint_root
362
- : null;
363
- const benchmarkMode = toStringOrNull(config?.benchmark_mode);
364
- const acceptanceMode = toStringOrNull(config?.acceptance_mode);
365
119
  const generationOrder = toStringArray(config?.generation_order);
366
120
  const inferenceRules = toStringArray(config?.inference_rules);
367
-
368
- if (parsed?.version === 2) {
369
- const legacyRootsAbsent = !("code_roots" in config)
370
- && !("docs_roots" in config)
371
- && !("structure_roots" in config);
372
- return {
373
- ok: String(parsed?.contract_ref ?? "") === ".nimi/contracts/spec-generation-inputs.schema.yaml"
374
- && mode === "class_filtered"
375
- && canonicalTargetRoot === ".nimi/spec"
376
- && legacyRootsAbsent
377
- && Array.isArray(codeInputs)
378
- && docsInputs.length > 0
379
- && docsInputs.every((entry) => isPlainObject(entry)
380
- && typeof entry.root === "string"
381
- && isAllowedV2AuthorityDocsRoot(entry.root)
382
- && Array.isArray(entry.allowed_surface_classes)
383
- && Array.isArray(entry.forbidden_surface_classes)
384
- && entry.use_as_authority === true)
385
- && Array.isArray(structureInputs)
386
- && Array.isArray(topicInputs)
387
- && Array.isArray(localInputs)
388
- && forbiddenSourceClasses.length > 0
389
- && generationOrder.includes("classify_inputs")
390
- && generationOrder.includes("validate_placement")
391
- && inferenceRules.includes("no_blanket_docs_roots")
392
- && SPEC_GENERATION_ACCEPTANCE_MODE_ENUM.includes(acceptanceMode)
393
- && topicLifecycleMarkdownPathsAreSortable(humanNotePaths),
394
- mode,
395
- canonicalTargetRoot,
396
- codeRoots: codeInputs.map((entry) => String(entry.root ?? "")).filter(Boolean),
397
- docsRoots: docsInputs.map((entry) => String(entry.root ?? "")).filter(Boolean),
398
- structureRoots: structureInputs.map((entry) => String(entry.root ?? "")).filter(Boolean),
399
- humanNotePaths,
400
- benchmarkBlueprintRoot,
401
- benchmarkMode: benchmarkMode ?? "none",
402
- acceptanceMode,
403
- generationOrder,
404
- inferenceRules,
405
- };
406
- }
121
+ const acceptanceMode = toStringOrNull(config?.acceptance_mode);
407
122
 
408
123
  return {
409
- ok: parsed?.version === 1
410
- && String(parsed?.contract_ref ?? "") === SPEC_GENERATION_INPUTS_CONTRACT_REF
411
- && SPEC_GENERATION_MODE_ENUM.includes(mode)
412
- && canonicalTargetRoot === ".nimi/spec"
413
- && Array.isArray(codeRoots)
414
- && Array.isArray(docsRoots)
415
- && Array.isArray(structureRoots)
416
- && Array.isArray(humanNotePaths)
417
- && topicLifecycleMarkdownPathsAreSortable(humanNotePaths)
418
- && BLUEPRINT_MODE_ENUM.includes(benchmarkMode)
419
- && SPEC_GENERATION_ACCEPTANCE_MODE_ENUM.includes(acceptanceMode)
420
- && generationOrder.length > 0
421
- && generationOrder.every((entry) => SPEC_GENERATION_ORDER_ENUM.includes(entry))
422
- && inferenceRules.length > 0
423
- && (
424
- benchmarkMode === "none"
425
- ? benchmarkBlueprintRoot === null
426
- : typeof benchmarkBlueprintRoot === "string" && benchmarkBlueprintRoot.length > 0
427
- ),
428
- mode,
429
- canonicalTargetRoot,
430
- codeRoots,
431
- docsRoots,
432
- structureRoots,
433
- humanNotePaths,
434
- benchmarkBlueprintRoot,
435
- benchmarkMode,
124
+ ok: hasExactFields(parsed, SPEC_GENERATION_INPUT_DOCUMENT_FIELDS)
125
+ && hasExactFields(config, SPEC_GENERATION_INPUT_FIELDS)
126
+ && parsed.version === 3
127
+ && String(parsed?.contract_ref ?? "") === ".nimi/contracts/spec-generation-inputs.schema.yaml"
128
+ && config?.mode === "class_filtered"
129
+ && config?.canonical_target_root === ".nimi/spec"
130
+ && docsInputs.length > 0
131
+ && docsInputs.every((entry) => isPlainObject(entry)
132
+ && isAllowedAuthorityRoot(entry.root)
133
+ && Array.isArray(entry.allowed_surface_classes)
134
+ && Array.isArray(entry.forbidden_surface_classes)
135
+ && entry.use_as_authority === true)
136
+ && Array.isArray(codeInputs)
137
+ && Array.isArray(structureInputs)
138
+ && Array.isArray(localInputs)
139
+ && forbiddenSourceClasses.length > 0
140
+ && generationOrder.includes("classify_inputs")
141
+ && generationOrder.includes("validate_placement")
142
+ && inferenceRules.includes("no_blanket_docs_roots")
143
+ && ACCEPTANCE_MODES.includes(acceptanceMode),
144
+ mode: toStringOrNull(config?.mode),
145
+ canonicalTargetRoot: toStringOrNull(config?.canonical_target_root),
146
+ codeRoots: codeInputs.map((entry) => String(entry?.root ?? "")).filter(Boolean),
147
+ docsRoots: docsInputs.map((entry) => String(entry?.root ?? "")).filter(Boolean),
148
+ structureRoots: structureInputs.map((entry) => String(entry?.root ?? "")).filter(Boolean),
149
+ localRoots: localInputs.map((entry) => String(entry?.root ?? "")).filter(Boolean),
150
+ humanNotePaths: [],
151
+ benchmarkBlueprintRoot: null,
152
+ benchmarkMode: "none",
436
153
  acceptanceMode,
437
154
  generationOrder,
438
155
  inferenceRules,
439
156
  };
440
157
  }
441
158
 
442
- export function parseSpecTreeModel(text) {
443
- const parsed = parseYamlText(text);
444
- const model = parsed?.spec_tree_model;
445
- const profile = toStringOrNull(model?.profile);
446
- const canonicalRoot = toStringOrNull(model?.canonical_root) ?? toStringOrNull(model?.product_authority_root);
447
- const authorityMode = normalizeAuthorityModeValue(toStringOrNull(model?.authority_mode));
448
- const isV2 = parsed?.version === 2;
449
- const domains = Array.isArray(model?.domains)
450
- ? model.domains.map(isV2 ? normalizeV2SpecDomain : normalizeSpecDomain).filter(Boolean)
451
- : [];
452
- const normativeClassSource = isV2 ? model?.product_authority_classes : model?.normative_classes;
453
- const derivedClassSource = isV2
454
- ? (Array.isArray(model?.non_authority_classes) ? model.non_authority_classes.filter((entry) => entry?.id === "derived_view") : [])
455
- : model?.derived_classes;
456
- const normativeClasses = Array.isArray(normativeClassSource)
457
- ? normativeClassSource.map(isV2 ? normalizeV2PathClass : normalizePathClass).filter(Boolean)
458
- : [];
459
- const derivedClasses = Array.isArray(derivedClassSource)
460
- ? derivedClassSource.map(isV2 ? (entry) => ({
461
- id: toStringOrNull(entry.id),
462
- pathPatterns: toStringArray(entry.allowed_roots),
463
- excludedPathPatterns: [],
464
- allowedExtensions: [],
465
- generatorRefs: [],
466
- mustReferenceNormativeIds: false,
467
- normative: false,
468
- }) : normalizePathClass).filter(Boolean)
469
- : [];
470
- const guidanceClasses = Array.isArray(model?.guidance_classes)
471
- ? model.guidance_classes.map(isV2 ? normalizeV2PathClass : normalizePathClass).filter(Boolean)
472
- : [];
473
- const requiredFilesByProfile = SPEC_TREE_PROFILE_ENUM.reduce((acc, currentProfile) => {
474
- acc[currentProfile] = toStringArray(model?.required_files?.[currentProfile]);
475
- return acc;
476
- }, {});
477
- if (isV2 && requiredFilesByProfile.surface_taxonomy_v1.length === 0) {
478
- requiredFilesByProfile.surface_taxonomy_v1 = requiredFilesByProfile.minimal;
479
- }
480
- const generatedPipelines = Array.isArray(model?.generated_pipelines)
481
- ? model.generated_pipelines.map(normalizeGeneratedPipeline).filter(Boolean)
482
- : [];
483
- const failClosedRules = toStringArray(model?.fail_closed_rules);
484
- const blueprintSource = isPlainObject(model?.blueprint_source)
485
- ? {
486
- mode: toStringOrNull(model.blueprint_source.mode),
487
- root: toStringOrNull(model.blueprint_source.root),
488
- equivalenceContractRef: toStringOrNull(model.blueprint_source.equivalence_contract_ref),
489
- }
490
- : null;
491
-
492
- const canonicalRootValid = canonicalRoot === ".nimi/spec";
493
- const profileValid = SPEC_TREE_PROFILE_ENUM.includes(profile);
494
- const authorityModeValid = AUTHORITY_MODE_ENUM.includes(authorityMode);
495
- const domainRootsValid = domains.length > 0 && domains.every((domain) => (
496
- typeof domain.id === "string"
497
- && typeof domain.root === "string"
498
- && typeof domain.normativeRoot === "string"
499
- && typeof domain.tablesRoot === "string"
500
- && pathStartsWithRoot(domain.root, canonicalRoot)
501
- && pathStartsWithRoot(domain.normativeRoot, domain.root)
502
- && pathStartsWithRoot(domain.tablesRoot, domain.normativeRoot)
503
- && (!domain.generatedRoot || pathStartsWithRoot(domain.generatedRoot, domain.normativeRoot))
504
- && domain.guidePaths.every((guidePath) => pathStartsWithRoot(guidePath, domain.root))
505
- ));
506
- const profilesToCheck = isV2 ? [profile] : SPEC_TREE_PROFILE_ENUM.filter((entry) => entry !== "surface_taxonomy_v1");
507
- const requiredFilesValid = profilesToCheck.every((currentProfile) => (
508
- requiredFilesByProfile[currentProfile].length > 0
509
- && requiredFilesByProfile[currentProfile].every((requiredPath) => pathStartsWithRoot(requiredPath, canonicalRoot))
510
- ));
511
- const fileClassIdsPresent = normativeClasses.every((entry) => entry.id && entry.pathPatterns.length > 0)
512
- && derivedClasses.every((entry) => entry.id && entry.pathPatterns.length > 0)
513
- && guidanceClasses.every((entry) => entry.id && entry.pathPatterns.length > 0);
514
- const generatedPipelinesValid = generatedPipelines.every((entry) => (
515
- entry.id
516
- && entry.ownerSurface
517
- && entry.generateCommand
518
- && entry.inputRoots.length > 0
519
- && entry.outputRoots.length > 0
520
- ));
521
- const blueprintSourceValid = !blueprintSource || (
522
- typeof blueprintSource.mode === "string"
523
- && ["repo_spec_blueprint", "custom_blueprint"].includes(blueprintSource.mode)
524
- && typeof blueprintSource.root === "string"
525
- && typeof blueprintSource.equivalenceContractRef === "string"
526
- && isDatePrefixedTopicLifecycleMarkdownPath(blueprintSource.equivalenceContractRef)
527
- );
528
-
529
- return {
530
- ok: [1, 2].includes(parsed?.version)
531
- && profileValid
532
- && canonicalRootValid
533
- && authorityModeValid
534
- && domainRootsValid
535
- && requiredFilesValid
536
- && fileClassIdsPresent
537
- && generatedPipelinesValid
538
- && failClosedRules.length > 0
539
- && blueprintSourceValid,
540
- version: parsed?.version ?? null,
541
- profile,
542
- canonicalRoot,
543
- authorityMode,
544
- domains,
545
- normativeClasses,
546
- derivedClasses,
547
- guidanceClasses,
548
- requiredFilesByProfile,
549
- generatedPipelines,
550
- failClosedRules,
551
- blueprintSource,
552
- };
553
- }
554
-
555
- export function parseCommandGatingMatrix(text) {
556
- const parsed = parseYamlText(text);
557
- const entries = Array.isArray(parsed?.command_gating_matrix)
558
- ? parsed.command_gating_matrix
559
- .filter((entry) => isPlainObject(entry) && typeof entry.command === "string")
560
- .map((entry) => ({
561
- command: entry.command,
562
- skill: toStringOrNull(entry.skill),
563
- allowedTreeStates: toStringArray(entry.allowed_tree_states),
564
- allowedAuthorityModes: toStringArray(entry.allowed_authority_modes).map(normalizeAuthorityModeValue),
565
- completedRequires: isPlainObject(entry.completed_requires) ? entry.completed_requires : null,
566
- requires: isPlainObject(entry.requires) ? entry.requires : null,
567
- notes: toStringArray(entry.notes),
568
- reports: toStringArray(entry.reports),
569
- }))
570
- : [];
571
-
572
- return {
573
- ok: parsed?.version === 1 && entries.length > 0,
574
- entries,
575
- };
576
- }
577
-
578
159
  export function parseBlueprintReference(text) {
579
160
  if (!text) {
580
161
  return {
@@ -593,14 +174,15 @@ export function parseBlueprintReference(text) {
593
174
  const root = toStringOrNull(reference?.root);
594
175
  const canonicalTargetRoot = toStringOrNull(reference?.canonical_target_root);
595
176
  const equivalenceContractRef = toStringOrNull(reference?.equivalence_contract_ref);
177
+ const localRefValid = equivalenceContractRef === null
178
+ || (equivalenceContractRef.startsWith(".nimi/local/") && !equivalenceContractRef.includes(".."));
596
179
 
597
180
  return {
598
- ok: parsed?.version === 1
181
+ ok: parsed?.version === 2
599
182
  && ["repo_spec_blueprint", "custom_blueprint"].includes(mode)
600
183
  && typeof root === "string"
601
- && typeof canonicalTargetRoot === "string"
602
- && typeof equivalenceContractRef === "string"
603
- && isDatePrefixedTopicLifecycleMarkdownPath(equivalenceContractRef),
184
+ && canonicalTargetRoot === ".nimi/spec"
185
+ && localRefValid,
604
186
  present: true,
605
187
  mode,
606
188
  root,
@@ -608,21 +190,3 @@ export function parseBlueprintReference(text) {
608
190
  equivalenceContractRef,
609
191
  };
610
192
  }
611
-
612
- export function matchCommandGatingRule(commandGatingMatrix, command, skillId = null) {
613
- if (!commandGatingMatrix?.entries) {
614
- return null;
615
- }
616
-
617
- return commandGatingMatrix.entries.find((entry) => {
618
- if (entry.command !== command) {
619
- return false;
620
- }
621
-
622
- if (skillId === null) {
623
- return !entry.skill;
624
- }
625
-
626
- return entry.skill === skillId;
627
- }) ?? null;
628
- }