@nimiplatform/nimi-coding 0.2.8 → 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.
- package/CHANGELOG.md +8 -92
- package/CONTRIBUTING.md +5 -34
- package/README.md +47 -350
- package/README.zh-CN.md +33 -287
- package/cli/commands/start.mjs +48 -688
- package/cli/commands/validate-spec-audit.mjs +1 -5
- package/cli/constants.mjs +9 -417
- package/cli/help.mjs +28 -145
- package/cli/index.mjs +5 -33
- package/cli/lib/blueprint-audit.mjs +5 -12
- package/cli/lib/bootstrap.mjs +0 -9
- package/cli/lib/contracts.mjs +0 -163
- package/cli/lib/doctor.mjs +155 -10
- package/cli/lib/entrypoints.mjs +63 -167
- package/cli/lib/internal/contracts-loaders.mjs +0 -85
- package/cli/lib/internal/contracts-parse.mjs +84 -520
- package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +13 -8
- package/cli/lib/internal/surface-taxonomy-validators.mjs +316 -66
- package/cli/lib/internal/validators-shared.mjs +0 -16
- package/cli/lib/internal/validators-spec-helpers.mjs +7 -140
- package/cli/lib/internal/validators-spec.mjs +103 -342
- package/cli/lib/shared.mjs +1 -42
- package/cli/lib/validators.mjs +0 -48
- package/cli/seeds/seed-policy.yaml +0 -3
- package/config/bootstrap.yaml +4 -4
- package/config/spec-generation-inputs.yaml +6 -12
- package/contracts/domain-admission.schema.yaml +3 -3
- package/contracts/migration-inventory.schema.yaml +12 -75
- package/contracts/negative-fixtures.yaml +19 -99
- package/contracts/placement-contract.schema.yaml +49 -78
- package/contracts/projection-edge.schema.yaml +37 -121
- package/contracts/shared-enums.yaml +4 -8
- package/contracts/spec-generation-inputs.schema.yaml +15 -112
- package/contracts/spec-layout.schema.yaml +32 -0
- package/contracts/surface-taxonomy.schema.yaml +43 -94
- package/contracts/table-family.schema.yaml +1 -1
- package/contracts/tracked-output-admission.schema.yaml +13 -66
- package/methodology/core.yaml +33 -25
- package/methodology/four-closure-policy.yaml +18 -26
- package/methodology/role-separation-policy.yaml +21 -27
- package/methodology/spec-reconstruction.yaml +17 -34
- package/package.json +2 -4
- package/spec/_meta/spec-tree-model.yaml +5 -101
- package/spec/product-scope.yaml +25 -57
- package/adapters/README.md +0 -25
- package/adapters/claude/README.md +0 -89
- package/adapters/claude/profile.yaml +0 -70
- package/adapters/codex/README.md +0 -53
- package/adapters/codex/profile.yaml +0 -78
- package/adapters/oh-my-codex/README.md +0 -184
- package/adapters/oh-my-codex/profile.yaml +0 -46
- package/cli/commands/admit-high-risk-decision.mjs +0 -108
- package/cli/commands/audit-sweep.mjs +0 -364
- package/cli/commands/closeout.mjs +0 -186
- package/cli/commands/decide-high-risk-execution.mjs +0 -124
- package/cli/commands/handoff.mjs +0 -123
- package/cli/commands/ingest-high-risk-execution.mjs +0 -95
- package/cli/commands/review-high-risk-execution.mjs +0 -95
- package/cli/commands/sweep-design.mjs +0 -295
- package/cli/commands/sweep.mjs +0 -22
- package/cli/commands/topic-formatters.mjs +0 -382
- package/cli/commands/topic-goal.mjs +0 -33
- package/cli/commands/topic-options-shared.mjs +0 -27
- package/cli/commands/topic-options-workflow.mjs +0 -767
- package/cli/commands/topic-options.mjs +0 -626
- package/cli/commands/topic-runner.mjs +0 -169
- package/cli/commands/topic.mjs +0 -795
- package/cli/commands/validate-acceptance.mjs +0 -5
- package/cli/commands/validate-execution-packet.mjs +0 -5
- package/cli/commands/validate-orchestration-state.mjs +0 -5
- package/cli/commands/validate-prompt.mjs +0 -5
- package/cli/commands/validate-worker-output.mjs +0 -5
- package/cli/lib/adapter-profiles.mjs +0 -403
- package/cli/lib/audit-execution.mjs +0 -52
- package/cli/lib/audit-sweep-runtime/admissions.mjs +0 -508
- package/cli/lib/audit-sweep-runtime/audit-validity.mjs +0 -356
- package/cli/lib/audit-sweep-runtime/chunks.mjs +0 -697
- package/cli/lib/audit-sweep-runtime/claude-auditor.mjs +0 -658
- package/cli/lib/audit-sweep-runtime/closeout.mjs +0 -144
- package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +0 -654
- package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +0 -527
- package/cli/lib/audit-sweep-runtime/common.mjs +0 -341
- package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +0 -172
- package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +0 -155
- package/cli/lib/audit-sweep-runtime/format.mjs +0 -57
- package/cli/lib/audit-sweep-runtime/ingest.mjs +0 -486
- package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +0 -425
- package/cli/lib/audit-sweep-runtime/inventory.mjs +0 -798
- package/cli/lib/audit-sweep-runtime/ledger.mjs +0 -315
- package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +0 -101
- package/cli/lib/audit-sweep-runtime/remediation.mjs +0 -349
- package/cli/lib/audit-sweep-runtime/rerun.mjs +0 -129
- package/cli/lib/audit-sweep-runtime/risk-budget.mjs +0 -300
- package/cli/lib/audit-sweep-runtime/status.mjs +0 -62
- package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +0 -215
- package/cli/lib/audit-sweep-runtime/validators.mjs +0 -797
- package/cli/lib/audit-sweep.mjs +0 -19
- package/cli/lib/authority-convergence.mjs +0 -720
- package/cli/lib/closeout.mjs +0 -732
- package/cli/lib/codex-sdk-runner.mjs +0 -76
- package/cli/lib/external-execution.mjs +0 -101
- package/cli/lib/handoff.mjs +0 -812
- package/cli/lib/high-risk-admission.mjs +0 -512
- package/cli/lib/high-risk-decision.mjs +0 -353
- package/cli/lib/high-risk-ingest.mjs +0 -321
- package/cli/lib/high-risk-review.mjs +0 -267
- package/cli/lib/internal/contracts-parse-high-risk.mjs +0 -131
- package/cli/lib/internal/contracts-validators.mjs +0 -399
- package/cli/lib/internal/doctor-bootstrap-surface.mjs +0 -406
- package/cli/lib/internal/doctor-delegated-surface.mjs +0 -256
- package/cli/lib/internal/doctor-finalize.mjs +0 -383
- package/cli/lib/internal/doctor-format.mjs +0 -286
- package/cli/lib/internal/doctor-inspectors.mjs +0 -327
- package/cli/lib/internal/doctor-state.mjs +0 -205
- package/cli/lib/internal/validators-artifacts.mjs +0 -515
- package/cli/lib/sweep-design-runtime/common.mjs +0 -246
- package/cli/lib/sweep-design-runtime/engine.mjs +0 -733
- package/cli/lib/sweep-design-runtime/fix-topic.mjs +0 -414
- package/cli/lib/sweep-design-runtime/lifecycle.mjs +0 -54
- package/cli/lib/sweep-design-runtime/results.mjs +0 -324
- package/cli/lib/sweep-design.mjs +0 -8
- package/cli/lib/topic-artifacts.mjs +0 -186
- package/cli/lib/topic-authority-coverage.mjs +0 -73
- package/cli/lib/topic-closeout.mjs +0 -560
- package/cli/lib/topic-common.mjs +0 -404
- package/cli/lib/topic-decisions.mjs +0 -332
- package/cli/lib/topic-draft-packets.mjs +0 -167
- package/cli/lib/topic-execution.mjs +0 -533
- package/cli/lib/topic-goal.mjs +0 -440
- package/cli/lib/topic-ledger.mjs +0 -281
- package/cli/lib/topic-lifecycle-artifacts.mjs +0 -173
- package/cli/lib/topic-root-validation.mjs +0 -288
- package/cli/lib/topic-runner-commands.mjs +0 -174
- package/cli/lib/topic-runner-deferral.mjs +0 -532
- package/cli/lib/topic-runner-stale-gates.mjs +0 -114
- package/cli/lib/topic-runner-validation.mjs +0 -138
- package/cli/lib/topic-runner.mjs +0 -727
- package/cli/lib/topic-scaffold.mjs +0 -252
- package/cli/lib/topic-waves.mjs +0 -403
- package/cli/lib/topic.mjs +0 -81
- package/config/audit-execution-artifacts.yaml +0 -20
- package/config/external-execution-artifacts.yaml +0 -16
- package/config/host-adapter.yaml +0 -30
- package/config/host-profile.yaml +0 -29
- package/config/installer-evidence.yaml +0 -31
- package/config/skill-installer.yaml +0 -23
- package/config/skill-manifest.yaml +0 -48
- package/config/skills.yaml +0 -30
- package/contracts/acceptance.schema.yaml +0 -16
- package/contracts/admission-checklist.schema.yaml +0 -15
- package/contracts/audit-chunk.schema.yaml +0 -123
- package/contracts/audit-closeout.schema.yaml +0 -51
- package/contracts/audit-finding.schema.yaml +0 -61
- package/contracts/audit-ledger.schema.yaml +0 -138
- package/contracts/audit-plan.schema.yaml +0 -138
- package/contracts/audit-remediation-map.schema.yaml +0 -52
- package/contracts/audit-rerun.schema.yaml +0 -31
- package/contracts/audit-sweep-result.yaml +0 -53
- package/contracts/authority-convergence-audit.schema.yaml +0 -19
- package/contracts/closeout.schema.yaml +0 -25
- package/contracts/decision-review.schema.yaml +0 -16
- package/contracts/doc-spec-audit-result.yaml +0 -19
- package/contracts/execution-packet.schema.yaml +0 -49
- package/contracts/external-host-compatibility.yaml +0 -22
- package/contracts/forbidden-shortcuts.catalog.yaml +0 -23
- package/contracts/high-risk-admission.schema.yaml +0 -23
- package/contracts/high-risk-execution-result.yaml +0 -20
- package/contracts/orchestration-state.schema.yaml +0 -41
- package/contracts/overflow-continuation.schema.yaml +0 -12
- package/contracts/packet.schema.yaml +0 -30
- package/contracts/pending-note.schema.yaml +0 -17
- package/contracts/prompt.schema.yaml +0 -12
- package/contracts/remediation.schema.yaml +0 -16
- package/contracts/result.schema.yaml +0 -24
- package/contracts/spec-reconstruction-result.yaml +0 -41
- package/contracts/sweep-design-result.yaml +0 -349
- package/contracts/topic-goal.schema.yaml +0 -87
- package/contracts/topic-run-ledger.schema.yaml +0 -72
- package/contracts/topic-step-decision.schema.yaml +0 -45
- package/contracts/topic.schema.yaml +0 -65
- package/contracts/true-close.schema.yaml +0 -15
- package/contracts/wave.schema.yaml +0 -29
- package/contracts/worker-output.schema.yaml +0 -15
- package/contracts/workflow-consumer.schema.yaml +0 -110
- package/methodology/audit-sweep-p0p1-recall.yaml +0 -45
- package/methodology/authority-convergence-policy.yaml +0 -42
- package/methodology/overflow-continuation-policy.yaml +0 -14
- package/methodology/skill-exchange-projection.yaml +0 -114
- package/methodology/skill-handoff.yaml +0 -34
- package/methodology/skill-installer-result.yaml +0 -27
- package/methodology/skill-installer-summary-projection.yaml +0 -181
- package/methodology/skill-runtime.yaml +0 -23
- package/methodology/spec-target-truth-profile.yaml +0 -46
- package/methodology/topic-lifecycle-report.yaml +0 -144
- package/methodology/topic-lifecycle.yaml +0 -37
- package/methodology/topic-naming-ontology.yaml +0 -21
- package/methodology/topic-ontology.yaml +0 -38
- package/methodology/topic-validation-policy.yaml +0 -9
- package/methodology/wave-dag-policy.yaml +0 -14
- package/spec/_meta/command-gating-matrix.yaml +0 -143
- package/spec/_meta/generate-drift-migration-checklist.yaml +0 -137
- package/spec/_meta/governance-routing-cutover-checklist.yaml +0 -35
- package/spec/_meta/phase2-impacted-surface-matrix.yaml +0 -44
- package/spec/_meta/spec-authority-cutover-readiness.yaml +0 -102
- 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
|
|
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
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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:
|
|
68
|
+
ok: parsed?.version === 2
|
|
280
69
|
&& String(parsed?.audit_contract?.id ?? "") === "canonical_spec_generation_audit"
|
|
281
|
-
&& String(parsed?.audit_contract?.target_ref ?? "") ===
|
|
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(
|
|
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 ===
|
|
96
|
+
ok: parsed?.version === 3
|
|
328
97
|
&& String(contract?.id ?? "") === "canonical_spec_generation_inputs"
|
|
329
|
-
&& String(contract?.
|
|
330
|
-
&& arraysEqual(toStringArray(
|
|
331
|
-
&& arraysEqual(
|
|
332
|
-
&&
|
|
333
|
-
&&
|
|
334
|
-
&&
|
|
335
|
-
&&
|
|
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
|
|
410
|
-
&&
|
|
411
|
-
&&
|
|
412
|
-
&&
|
|
413
|
-
&&
|
|
414
|
-
&&
|
|
415
|
-
&&
|
|
416
|
-
&&
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
&&
|
|
422
|
-
&&
|
|
423
|
-
&& (
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
)
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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 ===
|
|
181
|
+
ok: parsed?.version === 2
|
|
599
182
|
&& ["repo_spec_blueprint", "custom_blueprint"].includes(mode)
|
|
600
183
|
&& typeof root === "string"
|
|
601
|
-
&&
|
|
602
|
-
&&
|
|
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
|
-
}
|