@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,512 +0,0 @@
|
|
|
1
|
-
import { mkdir, realpath, writeFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
import YAML from "yaml";
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
HIGH_RISK_ADMISSION_CONTRACT_REF,
|
|
8
|
-
HIGH_RISK_ADMISSION_PAYLOAD_CONTRACT_VERSION,
|
|
9
|
-
} from "../constants.mjs";
|
|
10
|
-
import {
|
|
11
|
-
loadHighRiskAdmissionContract,
|
|
12
|
-
validateHighRiskAdmissionsSpec,
|
|
13
|
-
} from "./contracts.mjs";
|
|
14
|
-
import { inspectDoctorState } from "./doctor.mjs";
|
|
15
|
-
import { readTextIfFile } from "./fs-helpers.mjs";
|
|
16
|
-
import {
|
|
17
|
-
localize,
|
|
18
|
-
styleCommand,
|
|
19
|
-
styleHeading,
|
|
20
|
-
styleLabel,
|
|
21
|
-
styleStatus,
|
|
22
|
-
} from "./ui.mjs";
|
|
23
|
-
import { validateExecutionPacket } from "./validators.mjs";
|
|
24
|
-
import { isIsoUtcTimestamp, isPlainObject } from "./value-helpers.mjs";
|
|
25
|
-
import { parseYamlText } from "./yaml-helpers.mjs";
|
|
26
|
-
|
|
27
|
-
const ADMISSIONS_EVIDENCE_REF = ".nimi/local/high-risk-admissions.yaml";
|
|
28
|
-
|
|
29
|
-
function emptyAdmissionsEvidence() {
|
|
30
|
-
return {
|
|
31
|
-
admissions: [],
|
|
32
|
-
admission_rules: [
|
|
33
|
-
"explicit_manager_owned_decision_required_before_high_risk_local_evidence",
|
|
34
|
-
"mechanically_valid_admission_identity_required_before_high_risk_local_evidence",
|
|
35
|
-
"product_authority_change_requires_explicit_domain_spec_update",
|
|
36
|
-
],
|
|
37
|
-
semantic_constraints: [
|
|
38
|
-
"local_admission_records_must_not_promote_operational_runtime_state",
|
|
39
|
-
"local_admission_records_must_not_be_used_as_product_authority",
|
|
40
|
-
"local_admission_records_must_use_iso_8601_utc_admitted_at",
|
|
41
|
-
],
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function resolveProjectContainedPath(projectRoot, inputPath, artifactLabel) {
|
|
46
|
-
const absolutePath = path.resolve(projectRoot, inputPath);
|
|
47
|
-
let resolvedProjectRoot;
|
|
48
|
-
let resolvedPath;
|
|
49
|
-
try {
|
|
50
|
-
resolvedProjectRoot = await realpath(projectRoot);
|
|
51
|
-
resolvedPath = await realpath(absolutePath);
|
|
52
|
-
} catch {
|
|
53
|
-
return {
|
|
54
|
-
ok: false,
|
|
55
|
-
path: absolutePath,
|
|
56
|
-
reason: `cannot read ${artifactLabel} at ${absolutePath}`,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
const relative = path.relative(resolvedProjectRoot, resolvedPath);
|
|
60
|
-
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
61
|
-
return {
|
|
62
|
-
ok: false,
|
|
63
|
-
path: absolutePath,
|
|
64
|
-
reason: `${artifactLabel} must resolve inside the current project root`,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
ok: true,
|
|
69
|
-
path: resolvedPath,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function translateAdmissionReason(reason) {
|
|
74
|
-
const translations = new Map([
|
|
75
|
-
["imported decision payload must declare contractVersion nimicoding.high-risk-decision.v1", "导入的 decision payload 必须声明 contractVersion nimicoding.high-risk-decision.v1"],
|
|
76
|
-
["imported decision payload must declare skill.id high_risk_execution", "导入的 decision payload 必须声明 skill.id 为 high_risk_execution"],
|
|
77
|
-
["imported decision payload must remain localOnly true", "导入的 decision payload 必须保持 localOnly 为 true"],
|
|
78
|
-
["admit-high-risk-decision requires a decision payload with ok true", "admit-high-risk-decision 需要一个 ok 为 true 的 decision payload"],
|
|
79
|
-
["admit-high-risk-decision requires decisionStatus manager_decision_recorded", "admit-high-risk-decision 需要 decisionStatus 为 manager_decision_recorded"],
|
|
80
|
-
["admit-high-risk-decision requires mechanically valid acceptance state", "admit-high-risk-decision 需要机械校验通过的 acceptance 状态"],
|
|
81
|
-
["imported decision payload must include attachmentRefs.packet_ref", "导入的 decision payload 必须包含 attachmentRefs.packet_ref"],
|
|
82
|
-
["attached packet_ref failed mechanical validation", "附加的 packet_ref 未通过机械校验"],
|
|
83
|
-
["attached packet_ref is missing packet_id or topic_id", "附加的 packet_ref 缺少 packet_id 或 topic_id"],
|
|
84
|
-
["Bootstrap or handoff validation is failing; repair doctor errors before semantic admission", "bootstrap 或 handoff 校验失败;请先修复 doctor 报错,再进行语义准入"],
|
|
85
|
-
["Local admission evidence requires the canonical tree under `.nimi/spec`", "local admission evidence 需要 `.nimi/spec` 下的 canonical tree"],
|
|
86
|
-
["Manager-owned local decision is ready for explicit local admission evidence", "manager 拥有的本地 decision 已准备好写入显式 local admission evidence"],
|
|
87
|
-
]);
|
|
88
|
-
return translations.get(reason) ?? reason;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function loadImportedDecisionPayload(projectRoot, fromPath) {
|
|
92
|
-
const containedPath = await resolveProjectContainedPath(projectRoot, fromPath, "imported decision JSON");
|
|
93
|
-
if (!containedPath.ok) {
|
|
94
|
-
return {
|
|
95
|
-
ok: false,
|
|
96
|
-
error: `${localize(
|
|
97
|
-
`nimicoding admit-high-risk-decision refused: ${containedPath.reason}.`,
|
|
98
|
-
`nimicoding admit-high-risk-decision 已拒绝:${containedPath.reason}。`,
|
|
99
|
-
)}\n`,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const rawText = await readTextIfFile(containedPath.path);
|
|
104
|
-
|
|
105
|
-
if (rawText === null) {
|
|
106
|
-
return {
|
|
107
|
-
ok: false,
|
|
108
|
-
error: `${localize(
|
|
109
|
-
`nimicoding admit-high-risk-decision refused: cannot read imported decision JSON at ${containedPath.path}.`,
|
|
110
|
-
`nimicoding admit-high-risk-decision 已拒绝:无法读取 ${containedPath.path} 处的导入 decision JSON。`,
|
|
111
|
-
)}\n`,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
let parsed;
|
|
116
|
-
try {
|
|
117
|
-
parsed = JSON.parse(rawText);
|
|
118
|
-
} catch {
|
|
119
|
-
return {
|
|
120
|
-
ok: false,
|
|
121
|
-
error: `${localize(
|
|
122
|
-
`nimicoding admit-high-risk-decision refused: imported decision JSON at ${containedPath.path} is invalid JSON.`,
|
|
123
|
-
`nimicoding admit-high-risk-decision 已拒绝:${containedPath.path} 处的导入 decision JSON 不是合法 JSON。`,
|
|
124
|
-
)}\n`,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (!isPlainObject(parsed)) {
|
|
129
|
-
return {
|
|
130
|
-
ok: false,
|
|
131
|
-
error: `${localize(
|
|
132
|
-
"nimicoding admit-high-risk-decision refused: imported decision JSON must be an object.",
|
|
133
|
-
"nimicoding admit-high-risk-decision 已拒绝:导入的 decision JSON 必须是对象。",
|
|
134
|
-
)}\n`,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (parsed.projectRoot) {
|
|
139
|
-
let importedProjectRoot;
|
|
140
|
-
let currentProjectRoot;
|
|
141
|
-
try {
|
|
142
|
-
importedProjectRoot = await realpath(parsed.projectRoot);
|
|
143
|
-
currentProjectRoot = await realpath(projectRoot);
|
|
144
|
-
} catch {
|
|
145
|
-
return {
|
|
146
|
-
ok: false,
|
|
147
|
-
error: `${localize(
|
|
148
|
-
"nimicoding admit-high-risk-decision refused: imported decision projectRoot could not be resolved.",
|
|
149
|
-
"nimicoding admit-high-risk-decision 已拒绝:无法解析导入 decision 的 projectRoot。",
|
|
150
|
-
)}\n`,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (importedProjectRoot !== currentProjectRoot) {
|
|
155
|
-
return {
|
|
156
|
-
ok: false,
|
|
157
|
-
error: `${localize(
|
|
158
|
-
"nimicoding admit-high-risk-decision refused: imported decision projectRoot does not match the current project.",
|
|
159
|
-
"nimicoding admit-high-risk-decision 已拒绝:导入 decision 的 projectRoot 与当前项目不匹配。",
|
|
160
|
-
)}\n`,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
ok: true,
|
|
167
|
-
path: containedPath.path,
|
|
168
|
-
payload: parsed,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function validateImportedDecisionPayload(payload) {
|
|
173
|
-
if (payload.contractVersion !== "nimicoding.high-risk-decision.v1") {
|
|
174
|
-
return {
|
|
175
|
-
ok: false,
|
|
176
|
-
reason: "imported decision payload must declare contractVersion nimicoding.high-risk-decision.v1",
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (payload.skill?.id !== "high_risk_execution") {
|
|
181
|
-
return {
|
|
182
|
-
ok: false,
|
|
183
|
-
reason: "imported decision payload must declare skill.id high_risk_execution",
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (payload.localOnly !== true) {
|
|
188
|
-
return {
|
|
189
|
-
ok: false,
|
|
190
|
-
reason: "imported decision payload must remain localOnly true",
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (payload.ok !== true) {
|
|
195
|
-
return {
|
|
196
|
-
ok: false,
|
|
197
|
-
reason: "admit-high-risk-decision requires a decision payload with ok true",
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (payload.decisionStatus !== "manager_decision_recorded") {
|
|
202
|
-
return {
|
|
203
|
-
ok: false,
|
|
204
|
-
reason: "admit-high-risk-decision requires decisionStatus manager_decision_recorded",
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (payload.acceptanceValidation?.ok !== true) {
|
|
209
|
-
return {
|
|
210
|
-
ok: false,
|
|
211
|
-
reason: "admit-high-risk-decision requires mechanically valid acceptance state",
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (!isPlainObject(payload.attachmentRefs) || typeof payload.attachmentRefs.packet_ref !== "string") {
|
|
216
|
-
return {
|
|
217
|
-
ok: false,
|
|
218
|
-
reason: "imported decision payload must include attachmentRefs.packet_ref",
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return { ok: true };
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
async function loadAdmissionsEvidence(projectRoot, contract) {
|
|
226
|
-
const absolutePath = path.join(projectRoot, ADMISSIONS_EVIDENCE_REF);
|
|
227
|
-
const text = await readTextIfFile(absolutePath);
|
|
228
|
-
|
|
229
|
-
if (text === null) {
|
|
230
|
-
const parsed = emptyAdmissionsEvidence();
|
|
231
|
-
const validation = validateHighRiskAdmissionsSpec(parsed, contract);
|
|
232
|
-
return {
|
|
233
|
-
ok: validation.ok,
|
|
234
|
-
path: absolutePath,
|
|
235
|
-
parsed,
|
|
236
|
-
reason: validation.ok ? null : validation.reason,
|
|
237
|
-
initialized: true,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const parsed = parseYamlText(text);
|
|
242
|
-
const validation = validateHighRiskAdmissionsSpec(parsed, contract);
|
|
243
|
-
|
|
244
|
-
return {
|
|
245
|
-
ok: validation.ok,
|
|
246
|
-
path: absolutePath,
|
|
247
|
-
parsed,
|
|
248
|
-
reason: validation.ok ? null : validation.reason,
|
|
249
|
-
initialized: false,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
async function loadPacketIdentity(projectRoot, packetRef) {
|
|
254
|
-
const containedPath = await resolveProjectContainedPath(projectRoot, packetRef, "attached packet_ref");
|
|
255
|
-
if (!containedPath.ok) {
|
|
256
|
-
return {
|
|
257
|
-
ok: false,
|
|
258
|
-
reason: containedPath.reason,
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const packetValidation = await validateExecutionPacket(containedPath.path);
|
|
263
|
-
if (!packetValidation.ok) {
|
|
264
|
-
return {
|
|
265
|
-
ok: false,
|
|
266
|
-
reason: "attached packet_ref failed mechanical validation",
|
|
267
|
-
validation: packetValidation,
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const text = await readTextIfFile(containedPath.path);
|
|
272
|
-
const parsed = parseYamlText(text);
|
|
273
|
-
const packetId = String(parsed?.packet_id ?? "");
|
|
274
|
-
const topicId = String(parsed?.topic_id ?? "");
|
|
275
|
-
|
|
276
|
-
if (!packetId || !topicId) {
|
|
277
|
-
return {
|
|
278
|
-
ok: false,
|
|
279
|
-
reason: "attached packet_ref is missing packet_id or topic_id",
|
|
280
|
-
validation: packetValidation,
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return {
|
|
285
|
-
ok: true,
|
|
286
|
-
packetId,
|
|
287
|
-
topicId,
|
|
288
|
-
validation: packetValidation,
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function upsertAdmissionRecord(existingAdmissions, record) {
|
|
293
|
-
const nextAdmissions = existingAdmissions.filter((entry) => String(entry?.topic_id ?? "") !== record.topic_id);
|
|
294
|
-
const replaced = nextAdmissions.length !== existingAdmissions.length;
|
|
295
|
-
nextAdmissions.push(record);
|
|
296
|
-
nextAdmissions.sort((left, right) => String(left.topic_id).localeCompare(String(right.topic_id)));
|
|
297
|
-
return {
|
|
298
|
-
admissions: nextAdmissions,
|
|
299
|
-
action: replaced ? "updated" : "created",
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function evaluateAdmissionReadiness(doctorResult, admissionsEvidence, packetIdentity) {
|
|
304
|
-
if (!doctorResult.ok || !doctorResult.handoffReadiness.ok) {
|
|
305
|
-
return {
|
|
306
|
-
ok: false,
|
|
307
|
-
reason: "Bootstrap or handoff validation is failing; repair doctor errors before semantic admission",
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const v2Ready = doctorResult.specGenerationInputs?.mode === "class_filtered"
|
|
312
|
-
&& doctorResult.canonicalTree?.requiredFilesValid === true;
|
|
313
|
-
const legacyReady = doctorResult.lifecycleState?.treeState === "canonical_tree_ready"
|
|
314
|
-
&& doctorResult.canonicalTree?.requiredFilesValid === true;
|
|
315
|
-
if (!v2Ready && !legacyReady) {
|
|
316
|
-
return {
|
|
317
|
-
ok: false,
|
|
318
|
-
reason: "Local admission evidence requires canonical_tree_ready with declared canonical files present",
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (!admissionsEvidence.ok) {
|
|
323
|
-
return {
|
|
324
|
-
ok: false,
|
|
325
|
-
reason: admissionsEvidence.reason,
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (!packetIdentity.ok) {
|
|
330
|
-
return {
|
|
331
|
-
ok: false,
|
|
332
|
-
reason: packetIdentity.reason,
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return {
|
|
337
|
-
ok: true,
|
|
338
|
-
reason: "Manager-owned local decision is ready for explicit local admission evidence",
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export async function buildHighRiskAdmissionPayload(projectRoot, options) {
|
|
343
|
-
const imported = await loadImportedDecisionPayload(projectRoot, options.fromPath);
|
|
344
|
-
if (!imported.ok) {
|
|
345
|
-
return {
|
|
346
|
-
ok: false,
|
|
347
|
-
exitCode: 2,
|
|
348
|
-
inputError: true,
|
|
349
|
-
error: imported.error,
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const decisionValidation = validateImportedDecisionPayload(imported.payload);
|
|
354
|
-
if (!decisionValidation.ok) {
|
|
355
|
-
return {
|
|
356
|
-
ok: false,
|
|
357
|
-
exitCode: 2,
|
|
358
|
-
inputError: true,
|
|
359
|
-
error: `${localize(
|
|
360
|
-
`nimicoding admit-high-risk-decision refused: ${decisionValidation.reason}.`,
|
|
361
|
-
`nimicoding admit-high-risk-decision 已拒绝:${translateAdmissionReason(decisionValidation.reason)}。`,
|
|
362
|
-
)}\n`,
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (!isIsoUtcTimestamp(options.admittedAt)) {
|
|
367
|
-
return {
|
|
368
|
-
ok: false,
|
|
369
|
-
exitCode: 2,
|
|
370
|
-
inputError: true,
|
|
371
|
-
error: `${localize(
|
|
372
|
-
"nimicoding admit-high-risk-decision refused: --admitted-at must be an ISO-8601 UTC timestamp.",
|
|
373
|
-
"nimicoding admit-high-risk-decision 已拒绝:`--admitted-at` 必须是 ISO-8601 UTC 时间戳。",
|
|
374
|
-
)}\n`,
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const admissionsContract = await loadHighRiskAdmissionContract(projectRoot);
|
|
379
|
-
if (!admissionsContract.ok) {
|
|
380
|
-
return {
|
|
381
|
-
contractVersion: HIGH_RISK_ADMISSION_PAYLOAD_CONTRACT_VERSION,
|
|
382
|
-
ok: false,
|
|
383
|
-
exitCode: 1,
|
|
384
|
-
projectRoot,
|
|
385
|
-
sourceDecisionRef: imported.path,
|
|
386
|
-
semanticTargetRef: ADMISSIONS_EVIDENCE_REF,
|
|
387
|
-
artifactPath: path.join(projectRoot, ADMISSIONS_EVIDENCE_REF),
|
|
388
|
-
skill: {
|
|
389
|
-
id: "high_risk_execution",
|
|
390
|
-
},
|
|
391
|
-
localOnly: true,
|
|
392
|
-
admittedAt: options.admittedAt,
|
|
393
|
-
admissionAction: "blocked",
|
|
394
|
-
admissionRecord: null,
|
|
395
|
-
readiness: {
|
|
396
|
-
ok: false,
|
|
397
|
-
reason: `${HIGH_RISK_ADMISSION_CONTRACT_REF} is missing or malformed`,
|
|
398
|
-
},
|
|
399
|
-
doctor: {
|
|
400
|
-
ok: false,
|
|
401
|
-
handoffReadiness: { ok: false },
|
|
402
|
-
delegatedContracts: {},
|
|
403
|
-
},
|
|
404
|
-
nextEvidenceYaml: null,
|
|
405
|
-
nextAction: `${HIGH_RISK_ADMISSION_CONTRACT_REF} must satisfy the package-owned local admission evidence contract.`,
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const doctorResult = await inspectDoctorState(projectRoot);
|
|
410
|
-
const admissionsEvidence = await loadAdmissionsEvidence(projectRoot, admissionsContract);
|
|
411
|
-
const packetIdentity = await loadPacketIdentity(projectRoot, imported.payload.attachmentRefs.packet_ref);
|
|
412
|
-
const readiness = evaluateAdmissionReadiness(doctorResult, admissionsEvidence, packetIdentity);
|
|
413
|
-
|
|
414
|
-
const admissionRecord = packetIdentity.ok ? {
|
|
415
|
-
topic_id: packetIdentity.topicId,
|
|
416
|
-
packet_id: packetIdentity.packetId,
|
|
417
|
-
disposition: imported.payload.acceptanceDisposition,
|
|
418
|
-
admitted_at: options.admittedAt,
|
|
419
|
-
manager_review_owner: imported.payload.managerReviewOwner ?? doctorResult.delegatedContracts.semanticReviewOwner,
|
|
420
|
-
summary: typeof imported.payload.summary?.summary === "string" && imported.payload.summary.summary.trim().length > 0
|
|
421
|
-
? imported.payload.summary.summary
|
|
422
|
-
: `Admitted manager-owned disposition for ${packetIdentity.topicId}.`,
|
|
423
|
-
source_decision_contract: imported.payload.contractVersion,
|
|
424
|
-
} : null;
|
|
425
|
-
|
|
426
|
-
const nextAdmissions = readiness.ok
|
|
427
|
-
? upsertAdmissionRecord(admissionsEvidence.parsed.admissions, admissionRecord)
|
|
428
|
-
: { admissions: admissionsEvidence.parsed?.admissions ?? [], action: "blocked" };
|
|
429
|
-
|
|
430
|
-
const nextEvidenceObject = admissionsEvidence.ok ? {
|
|
431
|
-
admissions: nextAdmissions.admissions,
|
|
432
|
-
admission_rules: admissionsEvidence.parsed.admission_rules,
|
|
433
|
-
semantic_constraints: admissionsEvidence.parsed.semantic_constraints,
|
|
434
|
-
} : null;
|
|
435
|
-
const nextEvidenceValidation = nextEvidenceObject ? validateHighRiskAdmissionsSpec(nextEvidenceObject, admissionsContract) : { ok: false };
|
|
436
|
-
|
|
437
|
-
return {
|
|
438
|
-
contractVersion: HIGH_RISK_ADMISSION_PAYLOAD_CONTRACT_VERSION,
|
|
439
|
-
ok: readiness.ok && nextEvidenceValidation.ok,
|
|
440
|
-
exitCode: readiness.ok && nextEvidenceValidation.ok ? 0 : 1,
|
|
441
|
-
projectRoot,
|
|
442
|
-
sourceDecisionRef: imported.path,
|
|
443
|
-
semanticTargetRef: ADMISSIONS_EVIDENCE_REF,
|
|
444
|
-
artifactPath: path.join(projectRoot, ADMISSIONS_EVIDENCE_REF),
|
|
445
|
-
skill: {
|
|
446
|
-
id: "high_risk_execution",
|
|
447
|
-
},
|
|
448
|
-
localOnly: true,
|
|
449
|
-
admittedAt: options.admittedAt,
|
|
450
|
-
admissionAction: nextAdmissions.action,
|
|
451
|
-
admissionRecord,
|
|
452
|
-
readiness: readiness.ok && !nextEvidenceValidation.ok
|
|
453
|
-
? {
|
|
454
|
-
ok: false,
|
|
455
|
-
reason: nextEvidenceValidation.reason,
|
|
456
|
-
}
|
|
457
|
-
: readiness,
|
|
458
|
-
doctor: {
|
|
459
|
-
ok: doctorResult.ok,
|
|
460
|
-
handoffReadiness: doctorResult.handoffReadiness,
|
|
461
|
-
delegatedContracts: doctorResult.delegatedContracts,
|
|
462
|
-
},
|
|
463
|
-
nextEvidenceYaml: nextEvidenceObject ? YAML.stringify(nextEvidenceObject) : null,
|
|
464
|
-
nextAction: readiness.ok && nextEvidenceValidation.ok
|
|
465
|
-
? options.writeLocal
|
|
466
|
-
? `Write local admission evidence to ${ADMISSIONS_EVIDENCE_REF}.`
|
|
467
|
-
: `Review the local admission evidence preview or write it with --write-local.`
|
|
468
|
-
: readiness.ok && !nextEvidenceValidation.ok
|
|
469
|
-
? nextEvidenceValidation.reason
|
|
470
|
-
: readiness.reason,
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
export async function writeHighRiskAdmission(projectRoot, payload) {
|
|
475
|
-
if (!payload.ok || typeof payload.nextEvidenceYaml !== "string") {
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
await mkdir(path.dirname(path.join(projectRoot, ADMISSIONS_EVIDENCE_REF)), { recursive: true });
|
|
480
|
-
await writeFile(path.join(projectRoot, ADMISSIONS_EVIDENCE_REF), payload.nextEvidenceYaml, "utf8");
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
export function formatHighRiskAdmissionPayload(payload) {
|
|
484
|
-
const nextAction = payload.ok
|
|
485
|
-
? payload.nextAction.startsWith("Write local admission evidence to ")
|
|
486
|
-
? localize(payload.nextAction, `将 local admission evidence 写入 ${payload.semanticTargetRef}。`)
|
|
487
|
-
: localize(
|
|
488
|
-
payload.nextAction,
|
|
489
|
-
`检查 local admission evidence 预览,或使用 ${styleCommand("--write-local")} 将其写入。`,
|
|
490
|
-
)
|
|
491
|
-
: localize(payload.nextAction, translateAdmissionReason(payload.nextAction)
|
|
492
|
-
.replace(`${HIGH_RISK_ADMISSION_CONTRACT_REF} is missing or malformed`, `${HIGH_RISK_ADMISSION_CONTRACT_REF} 缺失或格式错误`)
|
|
493
|
-
.replace(`${HIGH_RISK_ADMISSION_CONTRACT_REF} must satisfy the package-owned local admission evidence contract.`, `${HIGH_RISK_ADMISSION_CONTRACT_REF} 必须满足包内 local admission evidence 契约。`));
|
|
494
|
-
const lines = [
|
|
495
|
-
styleHeading(`nimicoding admit-high-risk-decision: ${payload.projectRoot}`),
|
|
496
|
-
"",
|
|
497
|
-
styleLabel(localize("Admission:", "准入:")),
|
|
498
|
-
` - target_ref: ${payload.semanticTargetRef}`,
|
|
499
|
-
` - action: ${payload.admissionAction}`,
|
|
500
|
-
` - ready: ${styleStatus(payload.readiness.ok ? "ready" : "needs_attention")}`,
|
|
501
|
-
` - local_only: ${payload.localOnly ? "true" : "false"}`,
|
|
502
|
-
];
|
|
503
|
-
|
|
504
|
-
if (payload.admissionRecord) {
|
|
505
|
-
lines.push(` - topic_id: ${payload.admissionRecord.topic_id}`);
|
|
506
|
-
lines.push(` - packet_id: ${payload.admissionRecord.packet_id}`);
|
|
507
|
-
lines.push(` - disposition: ${payload.admissionRecord.disposition}`);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
lines.push("", styleLabel(localize("Next:", "下一步:")), ` - ${nextAction}`);
|
|
511
|
-
return `${lines.join("\n")}\n`;
|
|
512
|
-
}
|