@nimiplatform/nimi-coding 0.1.0 → 0.2.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.
- package/CHANGELOG.md +19 -0
- package/CODE_OF_CONDUCT.md +28 -0
- package/CONTRIBUTING.md +45 -0
- package/README.md +371 -344
- package/README.zh-CN.md +307 -0
- package/SECURITY.md +26 -0
- package/adapters/oh-my-codex/README.md +8 -9
- package/cli/commands/audit-sweep.mjs +10 -10
- package/cli/commands/classify-spec-tree.mjs +5 -0
- package/cli/commands/closeout.mjs +3 -0
- package/cli/commands/generate-spec-derived-docs.mjs +20 -0
- package/cli/commands/generate-spec-migration-plan.mjs +30 -0
- package/cli/commands/start.mjs +5 -1
- package/cli/commands/surface-validator-command.mjs +49 -0
- package/cli/commands/sweep-design.mjs +295 -0
- package/cli/commands/sweep.mjs +22 -0
- package/cli/commands/sync.mjs +132 -0
- package/cli/commands/topic-formatters.mjs +8 -8
- package/cli/commands/validate-ai-governance.mjs +167 -46
- package/cli/commands/validate-domain-admission.mjs +5 -0
- package/cli/commands/validate-guidance-bodies.mjs +5 -0
- package/cli/commands/validate-placement.mjs +5 -0
- package/cli/commands/validate-projection-edges.mjs +5 -0
- package/cli/commands/validate-spec-audit.mjs +5 -1
- package/cli/commands/validate-table-family.mjs +5 -0
- package/cli/commands/validate-tracked-output-admission.mjs +5 -0
- package/cli/constants.mjs +5 -49
- package/cli/help.mjs +33 -11
- package/cli/index.mjs +20 -2
- package/cli/lib/audit-sweep-runtime/admissions.mjs +38 -29
- package/cli/lib/audit-sweep-runtime/audit-validity.mjs +8 -0
- package/cli/lib/audit-sweep-runtime/chunks.mjs +11 -11
- package/cli/lib/audit-sweep-runtime/closeout.mjs +8 -8
- package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +3 -3
- package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +10 -10
- package/cli/lib/audit-sweep-runtime/common.mjs +7 -7
- package/cli/lib/audit-sweep-runtime/format.mjs +3 -3
- package/cli/lib/audit-sweep-runtime/ingest.mjs +8 -8
- package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +24 -27
- package/cli/lib/audit-sweep-runtime/inventory.mjs +58 -18
- package/cli/lib/audit-sweep-runtime/ledger.mjs +1 -1
- package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +2 -2
- package/cli/lib/audit-sweep-runtime/remediation.mjs +6 -6
- package/cli/lib/audit-sweep-runtime/rerun.mjs +6 -6
- package/cli/lib/audit-sweep-runtime/status.mjs +1 -1
- package/cli/lib/audit-sweep-runtime/validators.mjs +2 -2
- package/cli/lib/authority-convergence.mjs +397 -2
- package/cli/lib/blueprint-audit.mjs +5 -5
- package/cli/lib/closeout.mjs +126 -3
- package/cli/lib/contracts.mjs +21 -17
- package/cli/lib/handoff.mjs +29 -11
- package/cli/lib/high-risk-admission.mjs +60 -11
- package/cli/lib/high-risk-decision.mjs +31 -2
- package/cli/lib/high-risk-ingest.mjs +5 -1
- package/cli/lib/high-risk-review.mjs +5 -1
- package/cli/lib/internal/contracts-parse.mjs +195 -24
- package/cli/lib/internal/contracts-validators.mjs +3 -2
- package/cli/lib/internal/doctor-bootstrap-surface.mjs +82 -35
- package/cli/lib/internal/doctor-delegated-surface.mjs +1 -1
- package/cli/lib/internal/doctor-finalize.mjs +12 -8
- package/cli/lib/internal/doctor-inspectors.mjs +34 -1
- package/cli/lib/internal/governance/ai/ai-context-budget-core.mjs +74 -12
- package/cli/lib/internal/governance/ai/ai-structure-budget-core.mjs +24 -6
- package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +18 -23
- package/cli/lib/internal/surface-taxonomy-validators.mjs +931 -0
- package/cli/lib/internal/validators-spec.mjs +229 -20
- package/cli/lib/sweep-design-runtime/common.mjs +246 -0
- package/cli/lib/sweep-design-runtime/engine.mjs +733 -0
- package/cli/lib/sweep-design-runtime/fix-topic.mjs +414 -0
- package/cli/lib/sweep-design-runtime/lifecycle.mjs +54 -0
- package/cli/lib/sweep-design-runtime/results.mjs +324 -0
- package/cli/lib/sweep-design.mjs +8 -0
- package/cli/lib/sync.mjs +143 -0
- package/cli/lib/topic-artifacts.mjs +186 -0
- package/cli/lib/topic-authority-coverage.mjs +73 -0
- package/cli/lib/topic-closeout.mjs +560 -0
- package/cli/lib/topic-common.mjs +404 -0
- package/cli/lib/topic-decisions.mjs +332 -0
- package/cli/lib/topic-draft-packets.mjs +126 -7
- package/cli/lib/topic-execution.mjs +515 -0
- package/cli/lib/topic-goal.mjs +112 -33
- package/cli/lib/topic-ledger.mjs +281 -0
- package/cli/lib/topic-lifecycle-artifacts.mjs +173 -0
- package/cli/lib/topic-root-validation.mjs +288 -0
- package/cli/lib/topic-runner-commands.mjs +174 -0
- package/cli/lib/topic-runner-deferral.mjs +532 -0
- package/cli/lib/topic-runner-stale-gates.mjs +114 -0
- package/cli/lib/topic-runner-validation.mjs +138 -0
- package/cli/lib/topic-runner.mjs +109 -154
- package/cli/lib/topic-scaffold.mjs +252 -0
- package/cli/lib/topic-waves.mjs +403 -0
- package/cli/lib/topic.mjs +81 -93
- package/cli/lib/value-helpers.mjs +6 -1
- package/cli/seeds/bootstrap.mjs +96 -20
- package/cli/seeds/seed-policy.yaml +67 -0
- package/config/bootstrap.yaml +1 -1
- package/config/skill-manifest.yaml +4 -2
- package/config/spec-generation-inputs.yaml +41 -19
- package/contracts/audit-remediation-map.schema.yaml +1 -0
- package/contracts/audit-sweep-result.yaml +4 -0
- package/contracts/domain-admission.schema.yaml +56 -0
- package/contracts/migration-inventory.schema.yaml +80 -0
- package/contracts/negative-fixtures.yaml +91 -0
- package/contracts/placement-contract.schema.yaml +163 -0
- package/contracts/projection-edge.schema.yaml +130 -0
- package/contracts/shared-enums.yaml +68 -0
- package/contracts/spec-generation-audit.schema.yaml +19 -4
- package/contracts/spec-generation-inputs.schema.yaml +130 -29
- package/contracts/spec-reconstruction-result.yaml +9 -5
- package/contracts/surface-taxonomy.schema.yaml +201 -0
- package/contracts/sweep-design-result.yaml +349 -0
- package/contracts/table-family.schema.yaml +121 -0
- package/contracts/topic-goal.schema.yaml +10 -1
- package/contracts/tracked-output-admission.schema.yaml +70 -0
- package/contracts/workflow-consumer.schema.yaml +112 -0
- package/methodology/audit-sweep-p0p1-recall.yaml +1 -1
- package/methodology/spec-reconstruction.yaml +53 -30
- package/package.json +19 -4
- package/spec/_meta/command-gating-matrix.yaml +33 -0
- package/spec/_meta/generate-drift-migration-checklist.yaml +44 -62
- package/spec/_meta/governance-routing-cutover-checklist.yaml +3 -3
- package/spec/_meta/phase2-impacted-surface-matrix.yaml +14 -14
- package/spec/_meta/spec-authority-cutover-readiness.yaml +3 -5
- package/spec/_meta/spec-tree-model.yaml +104 -36
- package/spec/bootstrap-state.yaml +36 -36
- package/spec/product-scope.yaml +13 -10
|
@@ -36,7 +36,7 @@ export async function loadAuditSweepProjectConfig(projectRoot) {
|
|
|
36
36
|
} catch (error) {
|
|
37
37
|
return {
|
|
38
38
|
ok: false,
|
|
39
|
-
error: `nimicoding
|
|
39
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} must contain valid YAML (${error.message}).\n`,
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -47,25 +47,25 @@ export async function loadAuditSweepProjectConfig(projectRoot) {
|
|
|
47
47
|
if (!Array.isArray(rawExcludePatterns)) {
|
|
48
48
|
return {
|
|
49
49
|
ok: false,
|
|
50
|
-
error: `nimicoding
|
|
50
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} exclude_patterns must be an array.\n`,
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
if (!Array.isArray(rawIgnorePatterns)) {
|
|
54
54
|
return {
|
|
55
55
|
ok: false,
|
|
56
|
-
error: `nimicoding
|
|
56
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} ignore_patterns must be an array.\n`,
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
if (!Array.isArray(rawIgnoreOwnerDomains)) {
|
|
60
60
|
return {
|
|
61
61
|
ok: false,
|
|
62
|
-
error: `nimicoding
|
|
62
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} ignore_owner_domains must be an array.\n`,
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
if (rawIgnoreReason !== null && (typeof rawIgnoreReason !== "string" || rawIgnoreReason.trim().length === 0)) {
|
|
66
66
|
return {
|
|
67
67
|
ok: false,
|
|
68
|
-
error: `nimicoding
|
|
68
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} ignore_reason must be a non-empty string when present.\n`,
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -74,7 +74,7 @@ export async function loadAuditSweepProjectConfig(projectRoot) {
|
|
|
74
74
|
if (typeof pattern !== "string" || pattern.trim().length === 0) {
|
|
75
75
|
return {
|
|
76
76
|
ok: false,
|
|
77
|
-
error: `nimicoding
|
|
77
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} exclude_patterns entries must be non-empty strings.\n`,
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
excludePatterns.push(pattern.trim());
|
|
@@ -84,7 +84,7 @@ export async function loadAuditSweepProjectConfig(projectRoot) {
|
|
|
84
84
|
if (typeof pattern !== "string" || pattern.trim().length === 0) {
|
|
85
85
|
return {
|
|
86
86
|
ok: false,
|
|
87
|
-
error: `nimicoding
|
|
87
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} ignore_patterns entries must be non-empty strings.\n`,
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
ignorePatterns.push(pattern.trim());
|
|
@@ -94,7 +94,7 @@ export async function loadAuditSweepProjectConfig(projectRoot) {
|
|
|
94
94
|
if (typeof ownerDomain !== "string" || ownerDomain.trim().length === 0) {
|
|
95
95
|
return {
|
|
96
96
|
ok: false,
|
|
97
|
-
error: `nimicoding
|
|
97
|
+
error: `nimicoding sweep audit refused: ${AUDIT_SWEEP_PROJECT_CONFIG_REF} ignore_owner_domains entries must be non-empty strings.\n`,
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
100
|
ignoreOwnerDomains.push(ownerDomain.trim());
|
|
@@ -123,7 +123,7 @@ export async function loadAppSliceAdmissions(projectRoot) {
|
|
|
123
123
|
} catch (error) {
|
|
124
124
|
return {
|
|
125
125
|
ok: false,
|
|
126
|
-
error: `nimicoding
|
|
126
|
+
error: `nimicoding sweep audit refused: ${APP_SLICE_ADMISSION_REF} must contain valid YAML (${error.message}).\n`,
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -131,7 +131,7 @@ export async function loadAppSliceAdmissions(projectRoot) {
|
|
|
131
131
|
if (!rows) {
|
|
132
132
|
return {
|
|
133
133
|
ok: false,
|
|
134
|
-
error: `nimicoding
|
|
134
|
+
error: `nimicoding sweep audit refused: ${APP_SLICE_ADMISSION_REF} must declare admissions as an array.\n`,
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -146,20 +146,20 @@ export async function loadAppSliceAdmissions(projectRoot) {
|
|
|
146
146
|
? row.evidence_roots.map((entry) => String(entry ?? "").trim().replace(/\\/g, "/").replace(/\/$/, "")).filter(Boolean)
|
|
147
147
|
: null;
|
|
148
148
|
if (!appId || seenAppIds.has(appId)) {
|
|
149
|
-
return { ok: false, error: `nimicoding
|
|
149
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${APP_SLICE_ADMISSION_REF} has missing or duplicate app_id.\n` };
|
|
150
150
|
}
|
|
151
151
|
seenAppIds.add(appId);
|
|
152
152
|
if (appId === "avatar") {
|
|
153
|
-
return { ok: false, error: `nimicoding
|
|
153
|
+
return { ok: false, error: `nimicoding sweep audit refused: avatar is promoted to .nimi/spec/avatar and must not be admitted through ${APP_SLICE_ADMISSION_REF}.\n` };
|
|
154
154
|
}
|
|
155
155
|
if (status !== "active") {
|
|
156
156
|
continue;
|
|
157
157
|
}
|
|
158
158
|
if (!ownerDomain || !safeProjectRef(authorityRoot) || !authorityRoot.startsWith(`apps/${appId}/spec`)) {
|
|
159
|
-
return { ok: false, error: `nimicoding
|
|
159
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${APP_SLICE_ADMISSION_REF} ${appId} has invalid owner_domain or authority_root.\n` };
|
|
160
160
|
}
|
|
161
161
|
if (!evidenceRoots || evidenceRoots.length === 0 || !evidenceRoots.every((rootRef) => safeProjectRef(rootRef) && refInsideRoot(rootRef, `apps/${appId}`))) {
|
|
162
|
-
return { ok: false, error: `nimicoding
|
|
162
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${APP_SLICE_ADMISSION_REF} ${appId} has invalid evidence_roots.\n` };
|
|
163
163
|
}
|
|
164
164
|
admissions.push({
|
|
165
165
|
app_id: appId,
|
|
@@ -203,12 +203,12 @@ export async function loadAuditEvidenceRootAdmissions(projectRoot, listGitFiles,
|
|
|
203
203
|
} catch (error) {
|
|
204
204
|
return {
|
|
205
205
|
ok: false,
|
|
206
|
-
error: `nimicoding
|
|
206
|
+
error: `nimicoding sweep audit refused: ${tableRef} must contain valid YAML (${error.message}).\n`,
|
|
207
207
|
};
|
|
208
208
|
}
|
|
209
209
|
const rows = Array.isArray(parsed?.roots) ? parsed.roots : null;
|
|
210
210
|
if (!rows) {
|
|
211
|
-
return { ok: false, error: `nimicoding
|
|
211
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} must declare roots as an array.\n` };
|
|
212
212
|
}
|
|
213
213
|
for (const row of rows) {
|
|
214
214
|
const id = String(row?.id ?? "").trim();
|
|
@@ -220,13 +220,13 @@ export async function loadAuditEvidenceRootAdmissions(projectRoot, listGitFiles,
|
|
|
220
220
|
? row.evidence_roots.map((entry) => String(entry ?? "").trim().replace(/\\/g, "/").replace(/\/$/, "")).filter(Boolean)
|
|
221
221
|
: null;
|
|
222
222
|
if (!id || !ownerDomain || !authorityRefs?.length || !evidenceRoots?.length) {
|
|
223
|
-
return { ok: false, error: `nimicoding
|
|
223
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} root rows require id, owner_domain, authority_refs, and evidence_roots.\n` };
|
|
224
224
|
}
|
|
225
225
|
if (!authorityRefs.every((ref) => safeProjectRef(ref) && ref.startsWith(".nimi/spec/"))) {
|
|
226
|
-
return { ok: false, error: `nimicoding
|
|
226
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} ${id} authority_refs must stay under .nimi/spec.\n` };
|
|
227
227
|
}
|
|
228
228
|
if (!evidenceRoots.every((ref) => safeProjectRef(ref) && !ref.startsWith(".nimi/spec/"))) {
|
|
229
|
-
return { ok: false, error: `nimicoding
|
|
229
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} ${id} evidence_roots must be project evidence roots outside .nimi/spec.\n` };
|
|
230
230
|
}
|
|
231
231
|
admissions.push({
|
|
232
232
|
id,
|
|
@@ -256,12 +256,12 @@ export async function loadPackageAuthorityAdmissions(projectRoot, listGitFiles,
|
|
|
256
256
|
} catch (error) {
|
|
257
257
|
return {
|
|
258
258
|
ok: false,
|
|
259
|
-
error: `nimicoding
|
|
259
|
+
error: `nimicoding sweep audit refused: ${tableRef} must contain valid YAML (${error.message}).\n`,
|
|
260
260
|
};
|
|
261
261
|
}
|
|
262
262
|
const rows = Array.isArray(parsed?.admissions) ? parsed.admissions : null;
|
|
263
263
|
if (!rows) {
|
|
264
|
-
return { ok: false, error: `nimicoding
|
|
264
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} must declare admissions as an array.\n` };
|
|
265
265
|
}
|
|
266
266
|
for (const row of rows) {
|
|
267
267
|
const id = String(row?.id ?? "").trim();
|
|
@@ -279,28 +279,37 @@ export async function loadPackageAuthorityAdmissions(projectRoot, listGitFiles,
|
|
|
279
279
|
: [];
|
|
280
280
|
const admissionKey = `${tableRef}#${id}`;
|
|
281
281
|
if (!id || seenIds.has(admissionKey)) {
|
|
282
|
-
return { ok: false, error: `nimicoding
|
|
282
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} has missing or duplicate package authority id.\n` };
|
|
283
283
|
}
|
|
284
284
|
seenIds.add(admissionKey);
|
|
285
285
|
if (status !== "active") {
|
|
286
286
|
continue;
|
|
287
287
|
}
|
|
288
288
|
if (!ownerDomain || !safeProjectRef(authorityRoot) || authorityRoot.startsWith(".nimi/spec/") || !authorityRoot.endsWith("/spec")) {
|
|
289
|
-
return { ok: false, error: `nimicoding
|
|
289
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} ${id} has invalid owner_domain or authority_root.\n` };
|
|
290
290
|
}
|
|
291
291
|
if (!evidenceRoots || evidenceRoots.length === 0 || !evidenceRoots.every((rootRef) => safeProjectRef(rootRef) && !rootRef.startsWith(".nimi/spec/") && refInsideRoot(authorityRoot, rootRef))) {
|
|
292
|
-
return { ok: false, error: `nimicoding
|
|
292
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} ${id} has invalid evidence_roots.\n` };
|
|
293
293
|
}
|
|
294
294
|
const seenProjectionHostRefs = new Set();
|
|
295
295
|
for (const projection of hostAuthorityProjectionRefs) {
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
const hostProjectionAllowed = projection.host_ref.startsWith(".nimi/config/")
|
|
297
|
+
|| projection.host_ref.startsWith(".nimi/contracts/")
|
|
298
|
+
|| projection.host_ref.startsWith(".nimi/methodology/")
|
|
299
|
+
|| projection.host_ref.startsWith(".nimi/spec/");
|
|
300
|
+
if (!safeProjectRef(projection.host_ref) || !hostProjectionAllowed) {
|
|
301
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} ${id} host_authority_projection_refs host_ref must stay under .nimi config/contracts/methodology/spec projections.\n` };
|
|
298
302
|
}
|
|
299
|
-
|
|
300
|
-
|
|
303
|
+
const packageRoot = authorityRoot.replace(/\/spec$/, "");
|
|
304
|
+
const packageProjectionAllowed = projection.package_ref.startsWith(`${packageRoot}/config/`)
|
|
305
|
+
|| projection.package_ref.startsWith(`${packageRoot}/contracts/`)
|
|
306
|
+
|| projection.package_ref.startsWith(`${packageRoot}/methodology/`)
|
|
307
|
+
|| projection.package_ref.startsWith(`${packageRoot}/spec/`);
|
|
308
|
+
if (!safeProjectRef(projection.package_ref) || !packageProjectionAllowed) {
|
|
309
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} ${id} host_authority_projection_refs package_ref must stay under admitted package authority roots.\n` };
|
|
301
310
|
}
|
|
302
311
|
if (seenProjectionHostRefs.has(projection.host_ref)) {
|
|
303
|
-
return { ok: false, error: `nimicoding
|
|
312
|
+
return { ok: false, error: `nimicoding sweep audit refused: ${tableRef} ${id} host_authority_projection_refs contains duplicate host_ref.\n` };
|
|
304
313
|
}
|
|
305
314
|
seenProjectionHostRefs.add(projection.host_ref);
|
|
306
315
|
}
|
|
@@ -21,6 +21,7 @@ const REQUIRED_P0P1_RULE_CHECK_IDS = [
|
|
|
21
21
|
"provider_or_model_hardcoding",
|
|
22
22
|
"app_local_shadow_truth",
|
|
23
23
|
];
|
|
24
|
+
const REQUIRED_P0P1_RULE_CHECK_ID_SET = new Set(REQUIRED_P0P1_RULE_CHECK_IDS);
|
|
24
25
|
|
|
25
26
|
function validateP0P1RuleChecks(evidence, implementationRefSet) {
|
|
26
27
|
const ruleChecks = evidence?.coverage?.p0p1_rule_checks;
|
|
@@ -35,10 +36,17 @@ function validateP0P1RuleChecks(evidence, implementationRefSet) {
|
|
|
35
36
|
|
|
36
37
|
const checkedIds = [];
|
|
37
38
|
const invalid = [];
|
|
39
|
+
const seenIds = new Set();
|
|
38
40
|
for (const [index, check] of ruleChecks.entries()) {
|
|
39
41
|
const id = typeof check?.id === "string" ? check.id : "";
|
|
40
42
|
if (id) {
|
|
41
43
|
checkedIds.push(id);
|
|
44
|
+
if (!REQUIRED_P0P1_RULE_CHECK_ID_SET.has(id)) {
|
|
45
|
+
invalid.push({ index, id, reason: "id must exactly match an admitted P0/P1 rule check id" });
|
|
46
|
+
} else if (seenIds.has(id)) {
|
|
47
|
+
invalid.push({ index, id, reason: "duplicate P0/P1 rule check id" });
|
|
48
|
+
}
|
|
49
|
+
seenIds.add(id);
|
|
42
50
|
}
|
|
43
51
|
const status = check?.status;
|
|
44
52
|
if (!["checked", "not_applicable"].includes(status)) {
|
|
@@ -456,7 +456,7 @@ export function buildAuditorPacket(sweepId, chunk, auditor, dispatchedAt, plan,
|
|
|
456
456
|
finding_locations_must_belong_to_chunk_files_or_evidence_inventory: true,
|
|
457
457
|
authority_only_finding_location_policy: "when no implementation surface exists, findings[].location.file must be the in-scope authority_ref that contains the defect",
|
|
458
458
|
finding_contract_ref: ".nimi/contracts/audit-finding.schema.yaml",
|
|
459
|
-
ingest_command: `nimicoding
|
|
459
|
+
ingest_command: `nimicoding sweep audit chunk ingest --sweep-id ${sweepId} --chunk-id ${chunk.chunk_id} --from <audit-output.json> --verified-at <ISO-8601-UTC>`,
|
|
460
460
|
},
|
|
461
461
|
hard_constraints: [
|
|
462
462
|
"do_not_sample_out_files_from_this_chunk",
|
|
@@ -477,7 +477,7 @@ export function buildAuditorPacket(sweepId, chunk, auditor, dispatchedAt, plan,
|
|
|
477
477
|
export async function dispatchAuditSweepChunk(projectRoot, options) {
|
|
478
478
|
const sweepId = safeSweepId(options.sweepId);
|
|
479
479
|
if (!sweepId || typeof options.chunkId !== "string") {
|
|
480
|
-
return inputError("nimicoding
|
|
480
|
+
return inputError("nimicoding sweep audit refused: --sweep-id and --chunk-id are required.\n");
|
|
481
481
|
}
|
|
482
482
|
|
|
483
483
|
const timestampError = ensureIsoTimestamp(options.dispatchedAt, "--dispatched-at");
|
|
@@ -497,11 +497,11 @@ export async function dispatchAuditSweepChunk(projectRoot, options) {
|
|
|
497
497
|
}
|
|
498
498
|
|
|
499
499
|
if (chunkResult.chunk.state !== "planned") {
|
|
500
|
-
return inputError("nimicoding
|
|
500
|
+
return inputError("nimicoding sweep audit refused: chunk dispatch requires planned state.\n");
|
|
501
501
|
}
|
|
502
502
|
const budgetBlock = budgetBlockForChunk(planResult.plan, chunkResult.chunk);
|
|
503
503
|
if (budgetBlock) {
|
|
504
|
-
return inputError(`nimicoding
|
|
504
|
+
return inputError(`nimicoding sweep audit refused: ${budgetBlock}; build or admit remediation bundles before continuing discovery.\n`);
|
|
505
505
|
}
|
|
506
506
|
|
|
507
507
|
const updatedChunk = {
|
|
@@ -557,7 +557,7 @@ export async function dispatchAuditSweepChunk(projectRoot, options) {
|
|
|
557
557
|
export async function reviewAuditSweepChunk(projectRoot, options) {
|
|
558
558
|
const sweepId = safeSweepId(options.sweepId);
|
|
559
559
|
if (!sweepId || typeof options.chunkId !== "string") {
|
|
560
|
-
return inputError("nimicoding
|
|
560
|
+
return inputError("nimicoding sweep audit refused: --sweep-id and --chunk-id are required.\n");
|
|
561
561
|
}
|
|
562
562
|
|
|
563
563
|
const timestampError = ensureIsoTimestamp(options.reviewedAt, "--reviewed-at");
|
|
@@ -566,7 +566,7 @@ export async function reviewAuditSweepChunk(projectRoot, options) {
|
|
|
566
566
|
}
|
|
567
567
|
|
|
568
568
|
if (!["pass", "fail"].includes(options.verdict)) {
|
|
569
|
-
return inputError("nimicoding
|
|
569
|
+
return inputError("nimicoding sweep audit refused: --verdict must be pass or fail.\n");
|
|
570
570
|
}
|
|
571
571
|
|
|
572
572
|
return withAuditSweepMutationLock(projectRoot, sweepId, "chunk review", async () => {
|
|
@@ -581,10 +581,10 @@ export async function reviewAuditSweepChunk(projectRoot, options) {
|
|
|
581
581
|
}
|
|
582
582
|
|
|
583
583
|
if (chunkResult.chunk.state !== "ingested") {
|
|
584
|
-
return inputError("nimicoding
|
|
584
|
+
return inputError("nimicoding sweep audit refused: chunk review requires ingested state.\n");
|
|
585
585
|
}
|
|
586
586
|
if (options.verdict === "pass" && chunkResult.chunk.audit_validity?.posture === "invalid") {
|
|
587
|
-
return inputError("nimicoding
|
|
587
|
+
return inputError("nimicoding sweep audit refused: manager review cannot freeze invalid no-finding evidence as pass.\n");
|
|
588
588
|
}
|
|
589
589
|
|
|
590
590
|
const nextState = options.verdict === "pass" ? "frozen" : "failed";
|
|
@@ -636,14 +636,14 @@ export async function reviewAuditSweepChunk(projectRoot, options) {
|
|
|
636
636
|
export async function skipAuditSweepChunk(projectRoot, options) {
|
|
637
637
|
const sweepId = safeSweepId(options.sweepId);
|
|
638
638
|
if (!sweepId || typeof options.chunkId !== "string") {
|
|
639
|
-
return inputError("nimicoding
|
|
639
|
+
return inputError("nimicoding sweep audit refused: --sweep-id and --chunk-id are required.\n");
|
|
640
640
|
}
|
|
641
641
|
const timestampError = ensureIsoTimestamp(options.skippedAt, "--skipped-at");
|
|
642
642
|
if (timestampError) {
|
|
643
643
|
return timestampError;
|
|
644
644
|
}
|
|
645
645
|
if (typeof options.reason !== "string" || !options.reason.trim()) {
|
|
646
|
-
return inputError("nimicoding
|
|
646
|
+
return inputError("nimicoding sweep audit refused: --reason is required when skipping a chunk.\n");
|
|
647
647
|
}
|
|
648
648
|
|
|
649
649
|
return withAuditSweepMutationLock(projectRoot, sweepId, "chunk skip", async () => {
|
|
@@ -656,7 +656,7 @@ export async function skipAuditSweepChunk(projectRoot, options) {
|
|
|
656
656
|
return inputError(chunkResult.error);
|
|
657
657
|
}
|
|
658
658
|
if (chunkResult.chunk.state === "frozen") {
|
|
659
|
-
return inputError("nimicoding
|
|
659
|
+
return inputError("nimicoding sweep audit refused: frozen chunks cannot be skipped.\n");
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
const updatedChunk = {
|
|
@@ -22,7 +22,7 @@ import { validateAuditSweepArtifacts } from "./validators.mjs";
|
|
|
22
22
|
export async function buildAuditSweepCloseoutImport(projectRoot, options) {
|
|
23
23
|
const sweepId = safeSweepId(options.sweepId);
|
|
24
24
|
if (!sweepId) {
|
|
25
|
-
return inputError("nimicoding
|
|
25
|
+
return inputError("nimicoding sweep audit refused: --sweep-id is required.\n");
|
|
26
26
|
}
|
|
27
27
|
const timestampError = ensureIsoTimestamp(options.verifiedAt);
|
|
28
28
|
if (timestampError) {
|
|
@@ -37,16 +37,16 @@ export async function buildAuditSweepCloseoutImport(projectRoot, options) {
|
|
|
37
37
|
const preflightValidation = await validateAuditSweepArtifacts(projectRoot, { sweepId, scope: "remediation" });
|
|
38
38
|
if (!preflightValidation.ok) {
|
|
39
39
|
const failed = preflightValidation.checks.find((entry) => !entry.ok);
|
|
40
|
-
return inputError(`nimicoding
|
|
40
|
+
return inputError(`nimicoding sweep audit refused: sweep audit closeout preflight failed: ${failed?.reason ?? "artifact validation failed"}.\n`);
|
|
41
41
|
}
|
|
42
42
|
if (ledger.status === "blocked") {
|
|
43
|
-
return inputError("nimicoding
|
|
43
|
+
return inputError("nimicoding sweep audit refused: blocked ledger cannot produce completed closeout summary.\n");
|
|
44
44
|
}
|
|
45
45
|
if (ledger.status === "blocked_evidence_incomplete" || ledger.status === "partial_authority_only") {
|
|
46
|
-
return inputError("nimicoding
|
|
46
|
+
return inputError("nimicoding sweep audit refused: incomplete spec authority/evidence coverage cannot produce completed closeout summary.\n");
|
|
47
47
|
}
|
|
48
48
|
if (ledger.coverage.active_chunks > 0) {
|
|
49
|
-
return inputError("nimicoding
|
|
49
|
+
return inputError("nimicoding sweep audit refused: closeout summary requires no active chunks.\n");
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
const mapRef = remediationMapRef(sweepId, ledger.snapshot_id);
|
|
@@ -58,13 +58,13 @@ export async function buildAuditSweepCloseoutImport(projectRoot, options) {
|
|
|
58
58
|
: []);
|
|
59
59
|
const unmappedOpenFindings = openFindingIds.filter((findingId) => !mappedFindingIds.has(findingId));
|
|
60
60
|
if (openFindingIds.length > 0 && (!remediationMap || unmappedOpenFindings.length > 0)) {
|
|
61
|
-
return inputError("nimicoding
|
|
61
|
+
return inputError("nimicoding sweep audit refused: open findings require remediation map coverage before closeout summary.\n");
|
|
62
62
|
}
|
|
63
63
|
const closedWithoutResolutionEvidence = store.findings
|
|
64
64
|
.filter((finding) => finding.disposition !== "open")
|
|
65
65
|
.filter((finding) => !finding.resolution?.evidence_ref || !finding.resolution?.rerun);
|
|
66
66
|
if (closedWithoutResolutionEvidence.length > 0) {
|
|
67
|
-
return inputError("nimicoding
|
|
67
|
+
return inputError("nimicoding sweep audit refused: closed findings require resolution and rerun evidence before closeout summary.\n");
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const coverageStatus = deriveCoverageStatus(ledger.status);
|
|
@@ -125,7 +125,7 @@ export async function buildAuditSweepCloseoutImport(projectRoot, options) {
|
|
|
125
125
|
const closeoutValidation = await validateAuditSweepArtifacts(projectRoot, { sweepId, scope: "closeout" });
|
|
126
126
|
if (!closeoutValidation.ok) {
|
|
127
127
|
const failed = closeoutValidation.checks.find((entry) => !entry.ok);
|
|
128
|
-
return inputError(`nimicoding
|
|
128
|
+
return inputError(`nimicoding sweep audit refused: sweep audit closeout validation failed: ${failed?.reason ?? "artifact validation failed"}.\n`);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
return {
|
|
@@ -178,8 +178,8 @@ function isNonImplementationContextRef(ref) {
|
|
|
178
178
|
|| normalized.startsWith(".nimi/spec/")
|
|
179
179
|
|| normalized.startsWith(".nimi/contracts/")
|
|
180
180
|
|| normalized.startsWith(".nimi/methodology/")
|
|
181
|
-
|| normalized.startsWith("nimi-coding/methodology/")
|
|
182
|
-
|| normalized.startsWith("nimi-coding/spec/");
|
|
181
|
+
|| normalized.startsWith("package://@nimiplatform/nimi-coding/methodology/")
|
|
182
|
+
|| normalized.startsWith("package://@nimiplatform/nimi-coding/spec/");
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
function stripNonImplementationContextRefs(refs, evidenceInventorySet) {
|
|
@@ -562,7 +562,7 @@ function normalizeCodexSemanticOutput(rawOutput, chunk, options) {
|
|
|
562
562
|
auditor: {
|
|
563
563
|
id: typeof rawOutput.auditor?.id === "string" && rawOutput.auditor.id.trim() ? rawOutput.auditor.id : options.auditorId,
|
|
564
564
|
mode: "codex_semantic_audit",
|
|
565
|
-
methodology_ref: "nimi-coding/methodology/audit-sweep-p0p1-recall.yaml",
|
|
565
|
+
methodology_ref: "package://@nimiplatform/nimi-coding/methodology/audit-sweep-p0p1-recall.yaml",
|
|
566
566
|
provenance: {
|
|
567
567
|
kind: "semantic_audit",
|
|
568
568
|
packet_ref: options.packetRef,
|
|
@@ -42,7 +42,7 @@ function projectRefForPath(projectRoot, absolutePath) {
|
|
|
42
42
|
}
|
|
43
43
|
function codexPrompt({ packet, auditorPacketRef, rawRef, sessionRef }) {
|
|
44
44
|
return [
|
|
45
|
-
"You are the Codex semantic auditor for a nimicoding
|
|
45
|
+
"You are the Codex semantic auditor for a nimicoding sweep audit chunk.",
|
|
46
46
|
"Run in read-only, audit-only mode. Do not edit files. Do not implement product fixes.",
|
|
47
47
|
`Read the auditor packet from ${auditorPacketRef} and inspect the chunk authority refs and implementation evidence semantically.`,
|
|
48
48
|
"Do not rely on this prompt as the chunk inventory; the packet file is the source for files, authority_refs, selected_implementation_refs, audit_depth, retrieval_prepass, and the raw semantic output contract.",
|
|
@@ -59,7 +59,7 @@ function codexPrompt({ packet, auditorPacketRef, rawRef, sessionRef }) {
|
|
|
59
59
|
"The JSON object must have exactly these top-level fields: chunk_id, auditor, coverage, findings.",
|
|
60
60
|
`Set auditor.id to ${JSON.stringify(packet.auditor)}.`,
|
|
61
61
|
`Set auditor.mode to "codex_semantic_audit".`,
|
|
62
|
-
`Set auditor.methodology_ref to "nimi-coding/methodology/audit-sweep-p0p1-recall.yaml".`,
|
|
62
|
+
`Set auditor.methodology_ref to "package://@nimiplatform/nimi-coding/methodology/audit-sweep-p0p1-recall.yaml".`,
|
|
63
63
|
"Put P0/P1 rule checks only at coverage.p0p1_rule_checks.",
|
|
64
64
|
`Set auditor.provenance.kind to "semantic_audit".`,
|
|
65
65
|
`Set auditor.provenance.packet_ref to ${JSON.stringify(packetRef(packet.sweep_id, packet.chunk_id))}.`,
|
|
@@ -173,11 +173,11 @@ async function prepareCodexAuditPacket(projectRoot, options) {
|
|
|
173
173
|
return inputError(chunkResult.error);
|
|
174
174
|
}
|
|
175
175
|
if (chunkResult.chunk.state === "skipped") {
|
|
176
|
-
return inputError("nimicoding
|
|
176
|
+
return inputError("nimicoding sweep audit refused: skipped chunks cannot be audited through Codex.\n");
|
|
177
177
|
}
|
|
178
178
|
const budgetBlock = budgetBlockForChunk(planResult.plan, chunkResult.chunk);
|
|
179
179
|
if (budgetBlock && chunkResult.chunk.state !== "frozen") {
|
|
180
|
-
return inputError(`nimicoding
|
|
180
|
+
return inputError(`nimicoding sweep audit refused: ${budgetBlock}; build or admit remediation bundles before continuing discovery.\n`);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
const dispatch = {
|
|
@@ -311,7 +311,7 @@ async function markCodexAuditFailed(projectRoot, options) {
|
|
|
311
311
|
export async function runCodexAuditSweepChunk(projectRoot, options) {
|
|
312
312
|
const sweepId = safeSweepId(options.sweepId);
|
|
313
313
|
if (!sweepId || typeof options.chunkId !== "string") {
|
|
314
|
-
return inputError("nimicoding
|
|
314
|
+
return inputError("nimicoding sweep audit refused: --sweep-id and --chunk-id are required.\n");
|
|
315
315
|
}
|
|
316
316
|
const dispatchedAtError = ensureIsoTimestamp(options.dispatchedAt, "--dispatched-at");
|
|
317
317
|
if (dispatchedAtError) {
|
|
@@ -394,7 +394,7 @@ export async function runCodexAuditSweepChunk(projectRoot, options) {
|
|
|
394
394
|
timeout_ms: runResult.timeoutMs,
|
|
395
395
|
stderr_tail: runResult.stderr.slice(-2000),
|
|
396
396
|
});
|
|
397
|
-
return inputError(`nimicoding
|
|
397
|
+
return inputError(`nimicoding sweep audit refused: ${failureReason}\n`);
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
|
|
@@ -425,7 +425,7 @@ export async function runCodexAuditSweepChunk(projectRoot, options) {
|
|
|
425
425
|
transcript_ref: rawRef,
|
|
426
426
|
reason: extracted.error,
|
|
427
427
|
});
|
|
428
|
-
return inputError(`nimicoding
|
|
428
|
+
return inputError(`nimicoding sweep audit refused: Codex auditor output rejected for ${options.chunkId}: ${extracted.error}.\n`);
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
await appendRunEvent(projectRoot, sweepId, {
|
|
@@ -454,7 +454,7 @@ export async function runCodexAuditSweepChunk(projectRoot, options) {
|
|
|
454
454
|
phase: "chunk_ingest",
|
|
455
455
|
reason: `Codex auditor evidence ingest rejected: ${ingest.error ?? "unknown ingest failure"}.`,
|
|
456
456
|
});
|
|
457
|
-
return inputError(`nimicoding
|
|
457
|
+
return inputError(`nimicoding sweep audit refused: Codex auditor evidence ingest rejected for ${options.chunkId}: ${ingest.error ?? "unknown ingest failure"}.\n`);
|
|
458
458
|
}
|
|
459
459
|
|
|
460
460
|
const review = await reviewAuditSweepChunk(projectRoot, {
|
|
@@ -475,7 +475,7 @@ export async function runCodexAuditSweepChunk(projectRoot, options) {
|
|
|
475
475
|
phase: "chunk_review",
|
|
476
476
|
reason: `Codex auditor evidence review rejected: ${review.error ?? "unknown review failure"}.`,
|
|
477
477
|
});
|
|
478
|
-
return inputError(`nimicoding
|
|
478
|
+
return inputError(`nimicoding sweep audit refused: Codex auditor evidence review rejected for ${options.chunkId}: ${review.error ?? "unknown review failure"}.\n`);
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
const validation = await validateAuditSweepArtifacts(projectRoot, {
|
|
@@ -492,7 +492,7 @@ export async function runCodexAuditSweepChunk(projectRoot, options) {
|
|
|
492
492
|
phase: "post_chunk_validation",
|
|
493
493
|
reason: "Post-Codex chunk validation failed.",
|
|
494
494
|
});
|
|
495
|
-
return inputError(`nimicoding
|
|
495
|
+
return inputError(`nimicoding sweep audit refused: post-Codex chunk validation failed for ${options.chunkId}.\n`);
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
return {
|
|
@@ -97,7 +97,7 @@ export function resolveInsideProject(projectRoot, inputPath, label) {
|
|
|
97
97
|
if (!isPathInside(projectRoot, absolutePath)) {
|
|
98
98
|
return {
|
|
99
99
|
ok: false,
|
|
100
|
-
error: `nimicoding
|
|
100
|
+
error: `nimicoding sweep audit refused: ${label} must stay inside the project root.\n`,
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -168,7 +168,7 @@ export async function withAuditSweepMutationLock(projectRoot, sweepId, label, fn
|
|
|
168
168
|
handle = await open(lockPath, "wx");
|
|
169
169
|
} catch (error) {
|
|
170
170
|
if (error?.code === "EEXIST") {
|
|
171
|
-
return inputError(`nimicoding
|
|
171
|
+
return inputError(`nimicoding sweep audit refused: ${label} mutation already in progress for ${sweepId}; retry after the current command finishes.\n`);
|
|
172
172
|
}
|
|
173
173
|
throw error;
|
|
174
174
|
}
|
|
@@ -264,7 +264,7 @@ export async function loadPlan(projectRoot, sweepId) {
|
|
|
264
264
|
const ref = planRef(sweepId);
|
|
265
265
|
const plan = await loadYamlRef(projectRoot, ref);
|
|
266
266
|
if (!isPlainObject(plan) || plan.kind !== "audit-plan" || plan.sweep_id !== sweepId) {
|
|
267
|
-
return { ok: false, error: `nimicoding
|
|
267
|
+
return { ok: false, error: `nimicoding sweep audit refused: plan not found for ${sweepId}.\n` };
|
|
268
268
|
}
|
|
269
269
|
return { ok: true, plan, planRef: ref };
|
|
270
270
|
}
|
|
@@ -273,7 +273,7 @@ export async function loadChunk(projectRoot, sweepId, chunkId) {
|
|
|
273
273
|
const ref = chunkRef(sweepId, chunkId);
|
|
274
274
|
const chunk = await loadYamlRef(projectRoot, ref);
|
|
275
275
|
if (!isPlainObject(chunk) || chunk.kind !== "audit-chunk" || chunk.sweep_id !== sweepId || chunk.chunk_id !== chunkId) {
|
|
276
|
-
return { ok: false, error: `nimicoding
|
|
276
|
+
return { ok: false, error: `nimicoding sweep audit refused: chunk not found for ${sweepId}/${chunkId}.\n` };
|
|
277
277
|
}
|
|
278
278
|
return { ok: true, chunk, chunkRef: ref };
|
|
279
279
|
}
|
|
@@ -306,12 +306,12 @@ export async function loadLatestLedger(projectRoot, sweepId) {
|
|
|
306
306
|
const latestRef = artifactRef("ledger_ref", sweepId, "latest.yaml");
|
|
307
307
|
const pointer = await loadYamlRef(projectRoot, latestRef);
|
|
308
308
|
if (!isPlainObject(pointer) || typeof pointer.ledger_ref !== "string") {
|
|
309
|
-
return { ok: false, error: `nimicoding
|
|
309
|
+
return { ok: false, error: `nimicoding sweep audit refused: latest ledger not found for ${sweepId}.\n` };
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
const ledger = await loadYamlRef(projectRoot, pointer.ledger_ref);
|
|
313
313
|
if (!isPlainObject(ledger) || ledger.kind !== "audit-ledger" || ledger.sweep_id !== sweepId) {
|
|
314
|
-
return { ok: false, error: `nimicoding
|
|
314
|
+
return { ok: false, error: `nimicoding sweep audit refused: latest ledger is malformed for ${sweepId}.\n` };
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
return { ok: true, ledger, ledgerRef: pointer.ledger_ref, pointerRef: latestRef };
|
|
@@ -323,7 +323,7 @@ export function inputError(error) {
|
|
|
323
323
|
|
|
324
324
|
export function ensureIsoTimestamp(value, label = "--verified-at") {
|
|
325
325
|
if (!isIsoUtcTimestamp(value)) {
|
|
326
|
-
return inputError(`nimicoding
|
|
326
|
+
return inputError(`nimicoding sweep audit refused: ${label} must be an ISO-8601 UTC timestamp.\n`);
|
|
327
327
|
}
|
|
328
328
|
return null;
|
|
329
329
|
}
|
|
@@ -5,12 +5,12 @@ export function formatAuditSweepPayload(payload) {
|
|
|
5
5
|
}
|
|
6
6
|
if (payload.checks) {
|
|
7
7
|
const failed = payload.checks.filter((entry) => !entry.ok);
|
|
8
|
-
return `
|
|
8
|
+
return `sweep audit ${payload.sweepId ?? "result"} validation failed\nchecks: ${payload.checks.length - failed.length}/${payload.checks.length}\nfailed: ${failed.map((entry) => entry.reason).join("; ")}\n`;
|
|
9
9
|
}
|
|
10
|
-
return "
|
|
10
|
+
return "sweep audit failed\n";
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const lines = [`
|
|
13
|
+
const lines = [`sweep audit ${payload.sweepId ?? payload.auditCloseout?.sweep_id ?? "result"}`];
|
|
14
14
|
for (const [label, value] of [
|
|
15
15
|
["plan", payload.planRef],
|
|
16
16
|
["chunk", payload.chunkRef],
|
|
@@ -297,7 +297,7 @@ function recordClusteredSymptom(store, cluster, finding, fingerprint, classifica
|
|
|
297
297
|
export async function ingestAuditSweepChunk(projectRoot, options) {
|
|
298
298
|
const sweepId = safeSweepId(options.sweepId);
|
|
299
299
|
if (!sweepId || typeof options.chunkId !== "string") {
|
|
300
|
-
return inputError("nimicoding
|
|
300
|
+
return inputError("nimicoding sweep audit refused: --sweep-id and --chunk-id are required.\n");
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
const timestampError = ensureIsoTimestamp(options.verifiedAt);
|
|
@@ -311,7 +311,7 @@ export async function ingestAuditSweepChunk(projectRoot, options) {
|
|
|
311
311
|
}
|
|
312
312
|
const sourceInfo = await pathExists(source.absolutePath);
|
|
313
313
|
if (!sourceInfo || !sourceInfo.isFile()) {
|
|
314
|
-
return inputError("nimicoding
|
|
314
|
+
return inputError("nimicoding sweep audit refused: --from must point to an existing JSON file.\n");
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
return withAuditSweepMutationLock(projectRoot, sweepId, "chunk ingest", async () => {
|
|
@@ -324,20 +324,20 @@ export async function ingestAuditSweepChunk(projectRoot, options) {
|
|
|
324
324
|
return inputError(chunkResult.error);
|
|
325
325
|
}
|
|
326
326
|
if (chunkResult.chunk.state !== "dispatched") {
|
|
327
|
-
return inputError("nimicoding
|
|
327
|
+
return inputError("nimicoding sweep audit refused: chunk ingest requires dispatched state.\n");
|
|
328
328
|
}
|
|
329
329
|
|
|
330
330
|
const evidenceJson = await loadJsonFile(source.absolutePath);
|
|
331
331
|
if (!evidenceJson.ok) {
|
|
332
|
-
return inputError("nimicoding
|
|
332
|
+
return inputError("nimicoding sweep audit refused: --from must contain valid JSON.\n");
|
|
333
333
|
}
|
|
334
334
|
const envelope = validateEvidenceEnvelope(evidenceJson.value, chunkResult.chunk);
|
|
335
335
|
if (!envelope.ok) {
|
|
336
|
-
return inputError(`nimicoding
|
|
336
|
+
return inputError(`nimicoding sweep audit refused: ${envelope.error}.\n`);
|
|
337
337
|
}
|
|
338
338
|
const auditValidity = buildAuditValidityForEvidence(chunkResult.chunk, evidenceJson.value);
|
|
339
339
|
if (auditValidity.posture === "invalid") {
|
|
340
|
-
return inputError(`nimicoding
|
|
340
|
+
return inputError(`nimicoding sweep audit refused: audit evidence is invalid no-finding evidence (${auditValidity.blockers.map((blocker) => blocker.id).join(", ")}).\n`);
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
const evidenceRef = artifactRef("evidence_refs", sweepId, `${options.chunkId}.audit-evidence.json`);
|
|
@@ -355,11 +355,11 @@ export async function ingestAuditSweepChunk(projectRoot, options) {
|
|
|
355
355
|
for (const [index, rawFinding] of evidenceJson.value.findings.entries()) {
|
|
356
356
|
const normalized = normalizeFinding(rawFinding, index, chunkResult.chunk, sweepId, evidenceRef, options.verifiedAt);
|
|
357
357
|
if (!normalized.ok) {
|
|
358
|
-
return inputError(`nimicoding
|
|
358
|
+
return inputError(`nimicoding sweep audit refused: ${normalized.error}.\n`);
|
|
359
359
|
}
|
|
360
360
|
const clusterResult = deriveFindingCluster(rawFinding, normalized.finding, chunkResult.chunk, planResult.plan);
|
|
361
361
|
if (!clusterResult.ok) {
|
|
362
|
-
return inputError(`nimicoding
|
|
362
|
+
return inputError(`nimicoding sweep audit refused: finding ${index + 1} ${clusterResult.error}.\n`);
|
|
363
363
|
}
|
|
364
364
|
if (seen.has(normalized.fingerprint)) {
|
|
365
365
|
duplicateCount += 1;
|