@nimiplatform/nimi-coding 0.2.8 → 0.3.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 (206) hide show
  1. package/CHANGELOG.md +10 -90
  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/commands/validate-spec-governance.mjs +20 -0
  8. package/cli/constants.mjs +9 -417
  9. package/cli/help.mjs +28 -145
  10. package/cli/index.mjs +5 -33
  11. package/cli/lib/blueprint-audit.mjs +5 -12
  12. package/cli/lib/bootstrap.mjs +0 -9
  13. package/cli/lib/contracts.mjs +0 -163
  14. package/cli/lib/doctor.mjs +155 -10
  15. package/cli/lib/entrypoints.mjs +63 -167
  16. package/cli/lib/internal/contracts-loaders.mjs +0 -85
  17. package/cli/lib/internal/contracts-parse.mjs +84 -520
  18. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +13 -8
  19. package/cli/lib/internal/surface-taxonomy-validators.mjs +316 -66
  20. package/cli/lib/internal/validators-shared.mjs +0 -16
  21. package/cli/lib/internal/validators-spec-helpers.mjs +7 -140
  22. package/cli/lib/internal/validators-spec.mjs +103 -342
  23. package/cli/lib/shared.mjs +1 -42
  24. package/cli/lib/validators.mjs +0 -48
  25. package/cli/seeds/seed-policy.yaml +0 -3
  26. package/config/bootstrap.yaml +4 -4
  27. package/config/spec-generation-inputs.yaml +6 -12
  28. package/contracts/domain-admission.schema.yaml +3 -3
  29. package/contracts/migration-inventory.schema.yaml +12 -75
  30. package/contracts/negative-fixtures.yaml +19 -99
  31. package/contracts/placement-contract.schema.yaml +49 -78
  32. package/contracts/projection-edge.schema.yaml +37 -121
  33. package/contracts/shared-enums.yaml +4 -8
  34. package/contracts/spec-generation-inputs.schema.yaml +15 -112
  35. package/contracts/spec-layout.schema.yaml +32 -0
  36. package/contracts/surface-taxonomy.schema.yaml +43 -94
  37. package/contracts/table-family.schema.yaml +1 -1
  38. package/contracts/tracked-output-admission.schema.yaml +13 -66
  39. package/methodology/core.yaml +33 -25
  40. package/methodology/four-closure-policy.yaml +18 -26
  41. package/methodology/role-separation-policy.yaml +21 -27
  42. package/methodology/spec-reconstruction.yaml +17 -34
  43. package/package.json +2 -4
  44. package/spec/_meta/spec-tree-model.yaml +5 -101
  45. package/spec/product-scope.yaml +25 -57
  46. package/adapters/README.md +0 -25
  47. package/adapters/claude/README.md +0 -89
  48. package/adapters/claude/profile.yaml +0 -70
  49. package/adapters/codex/README.md +0 -53
  50. package/adapters/codex/profile.yaml +0 -78
  51. package/adapters/oh-my-codex/README.md +0 -184
  52. package/adapters/oh-my-codex/profile.yaml +0 -46
  53. package/cli/commands/admit-high-risk-decision.mjs +0 -108
  54. package/cli/commands/audit-sweep.mjs +0 -364
  55. package/cli/commands/closeout.mjs +0 -186
  56. package/cli/commands/decide-high-risk-execution.mjs +0 -124
  57. package/cli/commands/handoff.mjs +0 -123
  58. package/cli/commands/ingest-high-risk-execution.mjs +0 -95
  59. package/cli/commands/review-high-risk-execution.mjs +0 -95
  60. package/cli/commands/sweep-design.mjs +0 -295
  61. package/cli/commands/sweep.mjs +0 -22
  62. package/cli/commands/topic-formatters.mjs +0 -382
  63. package/cli/commands/topic-goal.mjs +0 -33
  64. package/cli/commands/topic-options-shared.mjs +0 -27
  65. package/cli/commands/topic-options-workflow.mjs +0 -767
  66. package/cli/commands/topic-options.mjs +0 -626
  67. package/cli/commands/topic-runner.mjs +0 -169
  68. package/cli/commands/topic.mjs +0 -795
  69. package/cli/commands/validate-acceptance.mjs +0 -5
  70. package/cli/commands/validate-execution-packet.mjs +0 -5
  71. package/cli/commands/validate-orchestration-state.mjs +0 -5
  72. package/cli/commands/validate-prompt.mjs +0 -5
  73. package/cli/commands/validate-worker-output.mjs +0 -5
  74. package/cli/lib/adapter-profiles.mjs +0 -403
  75. package/cli/lib/audit-execution.mjs +0 -52
  76. package/cli/lib/audit-sweep-runtime/admissions.mjs +0 -508
  77. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +0 -356
  78. package/cli/lib/audit-sweep-runtime/chunks.mjs +0 -697
  79. package/cli/lib/audit-sweep-runtime/claude-auditor.mjs +0 -658
  80. package/cli/lib/audit-sweep-runtime/closeout.mjs +0 -144
  81. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +0 -654
  82. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +0 -527
  83. package/cli/lib/audit-sweep-runtime/common.mjs +0 -341
  84. package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +0 -172
  85. package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +0 -155
  86. package/cli/lib/audit-sweep-runtime/format.mjs +0 -57
  87. package/cli/lib/audit-sweep-runtime/ingest.mjs +0 -486
  88. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +0 -425
  89. package/cli/lib/audit-sweep-runtime/inventory.mjs +0 -798
  90. package/cli/lib/audit-sweep-runtime/ledger.mjs +0 -315
  91. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +0 -101
  92. package/cli/lib/audit-sweep-runtime/remediation.mjs +0 -349
  93. package/cli/lib/audit-sweep-runtime/rerun.mjs +0 -129
  94. package/cli/lib/audit-sweep-runtime/risk-budget.mjs +0 -300
  95. package/cli/lib/audit-sweep-runtime/status.mjs +0 -62
  96. package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +0 -215
  97. package/cli/lib/audit-sweep-runtime/validators.mjs +0 -797
  98. package/cli/lib/audit-sweep.mjs +0 -19
  99. package/cli/lib/authority-convergence.mjs +0 -720
  100. package/cli/lib/closeout.mjs +0 -732
  101. package/cli/lib/codex-sdk-runner.mjs +0 -76
  102. package/cli/lib/external-execution.mjs +0 -101
  103. package/cli/lib/handoff.mjs +0 -812
  104. package/cli/lib/high-risk-admission.mjs +0 -512
  105. package/cli/lib/high-risk-decision.mjs +0 -353
  106. package/cli/lib/high-risk-ingest.mjs +0 -321
  107. package/cli/lib/high-risk-review.mjs +0 -267
  108. package/cli/lib/internal/contracts-parse-high-risk.mjs +0 -131
  109. package/cli/lib/internal/contracts-validators.mjs +0 -399
  110. package/cli/lib/internal/doctor-bootstrap-surface.mjs +0 -406
  111. package/cli/lib/internal/doctor-delegated-surface.mjs +0 -256
  112. package/cli/lib/internal/doctor-finalize.mjs +0 -383
  113. package/cli/lib/internal/doctor-format.mjs +0 -286
  114. package/cli/lib/internal/doctor-inspectors.mjs +0 -327
  115. package/cli/lib/internal/doctor-state.mjs +0 -205
  116. package/cli/lib/internal/validators-artifacts.mjs +0 -515
  117. package/cli/lib/sweep-design-runtime/common.mjs +0 -246
  118. package/cli/lib/sweep-design-runtime/engine.mjs +0 -733
  119. package/cli/lib/sweep-design-runtime/fix-topic.mjs +0 -414
  120. package/cli/lib/sweep-design-runtime/lifecycle.mjs +0 -54
  121. package/cli/lib/sweep-design-runtime/results.mjs +0 -324
  122. package/cli/lib/sweep-design.mjs +0 -8
  123. package/cli/lib/topic-artifacts.mjs +0 -186
  124. package/cli/lib/topic-authority-coverage.mjs +0 -73
  125. package/cli/lib/topic-closeout.mjs +0 -560
  126. package/cli/lib/topic-common.mjs +0 -404
  127. package/cli/lib/topic-decisions.mjs +0 -332
  128. package/cli/lib/topic-draft-packets.mjs +0 -167
  129. package/cli/lib/topic-execution.mjs +0 -533
  130. package/cli/lib/topic-goal.mjs +0 -440
  131. package/cli/lib/topic-ledger.mjs +0 -281
  132. package/cli/lib/topic-lifecycle-artifacts.mjs +0 -173
  133. package/cli/lib/topic-root-validation.mjs +0 -288
  134. package/cli/lib/topic-runner-commands.mjs +0 -174
  135. package/cli/lib/topic-runner-deferral.mjs +0 -532
  136. package/cli/lib/topic-runner-stale-gates.mjs +0 -114
  137. package/cli/lib/topic-runner-validation.mjs +0 -138
  138. package/cli/lib/topic-runner.mjs +0 -727
  139. package/cli/lib/topic-scaffold.mjs +0 -252
  140. package/cli/lib/topic-waves.mjs +0 -403
  141. package/cli/lib/topic.mjs +0 -81
  142. package/config/audit-execution-artifacts.yaml +0 -20
  143. package/config/external-execution-artifacts.yaml +0 -16
  144. package/config/host-adapter.yaml +0 -30
  145. package/config/host-profile.yaml +0 -29
  146. package/config/installer-evidence.yaml +0 -31
  147. package/config/skill-installer.yaml +0 -23
  148. package/config/skill-manifest.yaml +0 -48
  149. package/config/skills.yaml +0 -30
  150. package/contracts/acceptance.schema.yaml +0 -16
  151. package/contracts/admission-checklist.schema.yaml +0 -15
  152. package/contracts/audit-chunk.schema.yaml +0 -123
  153. package/contracts/audit-closeout.schema.yaml +0 -51
  154. package/contracts/audit-finding.schema.yaml +0 -61
  155. package/contracts/audit-ledger.schema.yaml +0 -138
  156. package/contracts/audit-plan.schema.yaml +0 -138
  157. package/contracts/audit-remediation-map.schema.yaml +0 -52
  158. package/contracts/audit-rerun.schema.yaml +0 -31
  159. package/contracts/audit-sweep-result.yaml +0 -53
  160. package/contracts/authority-convergence-audit.schema.yaml +0 -19
  161. package/contracts/closeout.schema.yaml +0 -25
  162. package/contracts/decision-review.schema.yaml +0 -16
  163. package/contracts/doc-spec-audit-result.yaml +0 -19
  164. package/contracts/execution-packet.schema.yaml +0 -49
  165. package/contracts/external-host-compatibility.yaml +0 -22
  166. package/contracts/forbidden-shortcuts.catalog.yaml +0 -23
  167. package/contracts/high-risk-admission.schema.yaml +0 -23
  168. package/contracts/high-risk-execution-result.yaml +0 -20
  169. package/contracts/orchestration-state.schema.yaml +0 -41
  170. package/contracts/overflow-continuation.schema.yaml +0 -12
  171. package/contracts/packet.schema.yaml +0 -30
  172. package/contracts/pending-note.schema.yaml +0 -17
  173. package/contracts/prompt.schema.yaml +0 -12
  174. package/contracts/remediation.schema.yaml +0 -16
  175. package/contracts/result.schema.yaml +0 -24
  176. package/contracts/spec-reconstruction-result.yaml +0 -41
  177. package/contracts/sweep-design-result.yaml +0 -349
  178. package/contracts/topic-goal.schema.yaml +0 -87
  179. package/contracts/topic-run-ledger.schema.yaml +0 -72
  180. package/contracts/topic-step-decision.schema.yaml +0 -45
  181. package/contracts/topic.schema.yaml +0 -65
  182. package/contracts/true-close.schema.yaml +0 -15
  183. package/contracts/wave.schema.yaml +0 -29
  184. package/contracts/worker-output.schema.yaml +0 -15
  185. package/contracts/workflow-consumer.schema.yaml +0 -110
  186. package/methodology/audit-sweep-p0p1-recall.yaml +0 -45
  187. package/methodology/authority-convergence-policy.yaml +0 -42
  188. package/methodology/overflow-continuation-policy.yaml +0 -14
  189. package/methodology/skill-exchange-projection.yaml +0 -114
  190. package/methodology/skill-handoff.yaml +0 -34
  191. package/methodology/skill-installer-result.yaml +0 -27
  192. package/methodology/skill-installer-summary-projection.yaml +0 -181
  193. package/methodology/skill-runtime.yaml +0 -23
  194. package/methodology/spec-target-truth-profile.yaml +0 -46
  195. package/methodology/topic-lifecycle-report.yaml +0 -144
  196. package/methodology/topic-lifecycle.yaml +0 -37
  197. package/methodology/topic-naming-ontology.yaml +0 -21
  198. package/methodology/topic-ontology.yaml +0 -38
  199. package/methodology/topic-validation-policy.yaml +0 -9
  200. package/methodology/wave-dag-policy.yaml +0 -14
  201. package/spec/_meta/command-gating-matrix.yaml +0 -143
  202. package/spec/_meta/generate-drift-migration-checklist.yaml +0 -137
  203. package/spec/_meta/governance-routing-cutover-checklist.yaml +0 -35
  204. package/spec/_meta/phase2-impacted-surface-matrix.yaml +0 -44
  205. package/spec/_meta/spec-authority-cutover-readiness.yaml +0 -102
  206. 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
- }