@deftai/directive-core 0.101.0 → 0.103.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/dist/authz/classify.js +97 -8
- package/dist/check/cached-orchestrator.d.ts +4 -0
- package/dist/check/cached-orchestrator.js +70 -5
- package/dist/check/cli-native-gates.d.ts +43 -0
- package/dist/check/cli-native-gates.js +84 -0
- package/dist/check/index.d.ts +1 -0
- package/dist/check/index.js +1 -0
- package/dist/check/named-cause.js +10 -0
- package/dist/doctor/checks.d.ts +5 -6
- package/dist/doctor/checks.js +13 -56
- package/dist/eval/later-graduation.d.ts +39 -0
- package/dist/eval/later-graduation.js +91 -0
- package/dist/eval/report.d.ts +6 -0
- package/dist/eval/report.js +27 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/init-deposit/hygiene.d.ts +7 -1
- package/dist/init-deposit/hygiene.js +11 -3
- package/dist/init-deposit/scaffold.d.ts +12 -0
- package/dist/init-deposit/scaffold.js +81 -8
- package/dist/intake/issue-ingest.js +42 -0
- package/dist/policy/ceremony-dial-escalation.d.ts +52 -0
- package/dist/policy/ceremony-dial-escalation.js +92 -0
- package/dist/policy/ceremony-dial.d.ts +3 -1
- package/dist/policy/ceremony-dial.js +52 -1
- package/dist/policy/check-resume.d.ts +9 -38
- package/dist/policy/check-resume.js +18 -156
- package/dist/policy/coverage-debt.d.ts +18 -37
- package/dist/policy/coverage-debt.js +38 -147
- package/dist/policy/index.d.ts +1 -1
- package/dist/policy/index.js +1 -1
- package/dist/product-first-done-gate/acceptance.js +22 -0
- package/dist/product-first-done-gate/empty-resolution.d.ts +26 -0
- package/dist/product-first-done-gate/empty-resolution.js +38 -0
- package/dist/product-first-done-gate/evaluate.d.ts +40 -2
- package/dist/product-first-done-gate/evaluate.js +253 -61
- package/dist/product-first-done-gate/index.d.ts +2 -1
- package/dist/product-first-done-gate/index.js +2 -1
- package/dist/product-first-done-gate/types.d.ts +3 -0
- package/dist/product-first-done-gate/types.js +0 -7
- package/dist/run-summary/emit.d.ts +11 -1
- package/dist/run-summary/emit.js +48 -2
- package/dist/run-summary/index.d.ts +2 -1
- package/dist/run-summary/index.js +2 -1
- package/dist/run-summary/path.d.ts +1 -1
- package/dist/run-summary/path.js +1 -1
- package/dist/run-summary/share.d.ts +25 -0
- package/dist/run-summary/share.js +106 -0
- package/dist/run-summary/types.d.ts +60 -2
- package/dist/run-summary/types.js +7 -0
- package/dist/scope/acceptance-activate-gate.d.ts +23 -0
- package/dist/scope/acceptance-activate-gate.js +70 -0
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/transition.js +5 -0
- package/dist/session/index.d.ts +0 -1
- package/dist/session/index.js +0 -1
- package/dist/session/orientation-compression.js +19 -9
- package/dist/session/session-start.d.ts +6 -0
- package/dist/session/session-start.js +44 -22
- package/dist/session/toolchain-preflight.d.ts +15 -0
- package/dist/session/toolchain-preflight.js +65 -5
- package/dist/verify-ac/clauses.d.ts +51 -0
- package/dist/verify-ac/clauses.js +490 -0
- package/dist/verify-ac/evaluate.d.ts +73 -0
- package/dist/verify-ac/evaluate.js +167 -0
- package/dist/verify-ac/flag.d.ts +35 -0
- package/dist/verify-ac/flag.js +104 -0
- package/dist/verify-ac/index.d.ts +10 -0
- package/dist/verify-ac/index.js +10 -0
- package/package.json +7 -3
- package/dist/policy/coverage-check-resume-presets.d.ts +0 -46
- package/dist/policy/coverage-check-resume-presets.js +0 -228
- package/dist/session/coverage-check-resume-nudge.d.ts +0 -34
- package/dist/session/coverage-check-resume-nudge.js +0 -66
|
@@ -1,34 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Coverage-debt hatch policy (#3189).
|
|
2
|
+
* Coverage-debt hatch policy (#3189 / #3314).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Non-goal: a consumer tree never auto-files coverage-debt issues on
|
|
9
|
-
* deftai/directive -- ledger is always THIS repo.
|
|
4
|
+
* Plain optional setting. Default off. Fail-closed when absent or invalid.
|
|
5
|
+
* Hatch / auto-file are reserved — not a ship gate. Live hatch is
|
|
6
|
+
* `--allow-coverage-debt=#N` (#2866).
|
|
10
7
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { policyColonInvocation } from "./policy-invocation.js";
|
|
15
|
-
import { appendAuditLog, loadProjectDefinition, projectDefinitionPath } from "./resolve.js";
|
|
8
|
+
import { resolveCheckResume } from "./check-resume.js";
|
|
9
|
+
import { readPlanPolicy } from "./plan-extensions.js";
|
|
10
|
+
import { loadProjectDefinition } from "./resolve.js";
|
|
16
11
|
/** Canonical registered policy field name. */
|
|
17
12
|
export const FIELD_COVERAGE_DEBT = "plan.policy.coverageDebt";
|
|
18
13
|
/** Short alias for `policy:show --field=coverageDebt`. */
|
|
19
14
|
export const FIELD_COVERAGE_DEBT_CLI_ALIAS = "coverageDebt";
|
|
20
|
-
export const COVERAGE_DEBT_STATUSES = ["unset", "decided"];
|
|
21
15
|
export const COVERAGE_DEBT_MODES = ["off", "warn", "hatch"];
|
|
22
|
-
/** Fail-closed effective mode when
|
|
16
|
+
/** Fail-closed effective mode when absent / missing / invalid. */
|
|
23
17
|
export const DEFAULT_COVERAGE_DEBT_MODE = "off";
|
|
24
18
|
/** Consumers default autoFile false even under hatch mode. */
|
|
25
19
|
export const DEFAULT_COVERAGE_DEBT_AUTO_FILE = false;
|
|
26
20
|
function defaultResolved(source, error = null) {
|
|
27
21
|
return {
|
|
28
|
-
status: "unset",
|
|
29
22
|
mode: DEFAULT_COVERAGE_DEBT_MODE,
|
|
30
23
|
autoFile: DEFAULT_COVERAGE_DEBT_AUTO_FILE,
|
|
31
|
-
dismissReason: null,
|
|
32
24
|
source,
|
|
33
25
|
error,
|
|
34
26
|
};
|
|
@@ -36,10 +28,7 @@ function defaultResolved(source, error = null) {
|
|
|
36
28
|
function isMode(value) {
|
|
37
29
|
return typeof value === "string" && COVERAGE_DEBT_MODES.includes(value);
|
|
38
30
|
}
|
|
39
|
-
|
|
40
|
-
return typeof value === "string" && COVERAGE_DEBT_STATUSES.includes(value);
|
|
41
|
-
}
|
|
42
|
-
/** Validate a `plan.policy.coverageDebt` payload. */
|
|
31
|
+
/** Validate a `plan.policy.coverageDebt` payload. Extra keys are ignored. */
|
|
43
32
|
export function validateCoverageDebt(value) {
|
|
44
33
|
if (value === null || value === undefined) {
|
|
45
34
|
return [];
|
|
@@ -49,25 +38,17 @@ export function validateCoverageDebt(value) {
|
|
|
49
38
|
}
|
|
50
39
|
const rec = value;
|
|
51
40
|
const errors = [];
|
|
52
|
-
if ("status" in rec && !isStatus(rec.status)) {
|
|
53
|
-
errors.push(`${FIELD_COVERAGE_DEBT}.status must be one of ${COVERAGE_DEBT_STATUSES.join("|")}`);
|
|
54
|
-
}
|
|
55
41
|
if ("mode" in rec && !isMode(rec.mode)) {
|
|
56
42
|
errors.push(`${FIELD_COVERAGE_DEBT}.mode must be one of ${COVERAGE_DEBT_MODES.join("|")}`);
|
|
57
43
|
}
|
|
58
44
|
if ("autoFile" in rec && typeof rec.autoFile !== "boolean") {
|
|
59
45
|
errors.push(`${FIELD_COVERAGE_DEBT}.autoFile must be a boolean`);
|
|
60
46
|
}
|
|
61
|
-
if ("dismissReason" in rec &&
|
|
62
|
-
rec.dismissReason !== null &&
|
|
63
|
-
typeof rec.dismissReason !== "string") {
|
|
64
|
-
errors.push(`${FIELD_COVERAGE_DEBT}.dismissReason must be a string or null`);
|
|
65
|
-
}
|
|
66
47
|
return errors;
|
|
67
48
|
}
|
|
68
49
|
/**
|
|
69
|
-
* Resolve a typed block. Missing/invalid → fail-closed mode off
|
|
70
|
-
*
|
|
50
|
+
* Resolve a typed block. Missing/invalid → fail-closed mode off.
|
|
51
|
+
* `mode` is the setting; leftover ritual fields (status/dismissReason) are ignored.
|
|
71
52
|
*/
|
|
72
53
|
export function resolveCoverageDebtFromTypedBlock(raw) {
|
|
73
54
|
const errors = validateCoverageDebt(raw);
|
|
@@ -78,26 +59,17 @@ export function resolveCoverageDebtFromTypedBlock(raw) {
|
|
|
78
59
|
return defaultResolved("default");
|
|
79
60
|
}
|
|
80
61
|
const block = raw;
|
|
81
|
-
const status = isStatus(block.status) ? block.status : "unset";
|
|
82
62
|
const mode = isMode(block.mode) ? block.mode : DEFAULT_COVERAGE_DEBT_MODE;
|
|
83
|
-
// Fail-closed: hatch modes only apply when decided.
|
|
84
|
-
const effectiveMode = status === "decided" ? mode : DEFAULT_COVERAGE_DEBT_MODE;
|
|
85
63
|
const autoFileRaw = typeof block.autoFile === "boolean" ? block.autoFile : DEFAULT_COVERAGE_DEBT_AUTO_FILE;
|
|
86
|
-
|
|
87
|
-
const autoFile = effectiveMode === "hatch" ? autoFileRaw : false;
|
|
88
|
-
const dismissReason = typeof block.dismissReason === "string" && block.dismissReason.trim().length > 0
|
|
89
|
-
? block.dismissReason.trim()
|
|
90
|
-
: null;
|
|
64
|
+
const autoFile = mode === "hatch" ? autoFileRaw : false;
|
|
91
65
|
return {
|
|
92
|
-
|
|
93
|
-
mode: status === "decided" ? mode : DEFAULT_COVERAGE_DEBT_MODE,
|
|
66
|
+
mode,
|
|
94
67
|
autoFile,
|
|
95
|
-
dismissReason: status === "decided" ? dismissReason : null,
|
|
96
68
|
source: "typed",
|
|
97
69
|
error: null,
|
|
98
70
|
};
|
|
99
71
|
}
|
|
100
|
-
/** Resolve `plan.policy.coverageDebt` from PROJECT-DEFINITION (#
|
|
72
|
+
/** Resolve `plan.policy.coverageDebt` from PROJECT-DEFINITION (#3314). */
|
|
101
73
|
export function resolveCoverageDebt(projectRoot) {
|
|
102
74
|
const [data, err] = loadProjectDefinition(projectRoot);
|
|
103
75
|
if (data === null) {
|
|
@@ -112,40 +84,28 @@ export function resolveCoverageDebt(projectRoot) {
|
|
|
112
84
|
}
|
|
113
85
|
return resolveCoverageDebtFromTypedBlock(policyBlock.coverageDebt);
|
|
114
86
|
}
|
|
115
|
-
/** Effective hatch soft-pass allowed only when
|
|
87
|
+
/** Effective hatch soft-pass allowed only when mode=hatch. Reserved — unused by check/release. */
|
|
116
88
|
export function isCoverageDebtHatchAllowed(policy) {
|
|
117
|
-
return policy.
|
|
89
|
+
return policy.mode === "hatch";
|
|
118
90
|
}
|
|
119
91
|
/** Auto-file debt issues only when hatch is allowed AND autoFile true. */
|
|
120
92
|
export function isCoverageDebtAutoFileAllowed(policy) {
|
|
121
93
|
return isCoverageDebtHatchAllowed(policy) && policy.autoFile === true;
|
|
122
94
|
}
|
|
123
|
-
/**
|
|
124
|
-
* Non-goal guard (#3189): consumer trees never auto-file coverage-debt on
|
|
125
|
-
* deftai/directive. Ledger is always the project under check.
|
|
126
|
-
*/
|
|
127
|
-
export function coverageDebtLedgerRepoIsSelfOnly() {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
95
|
export function formatCoverageDebtStatusLine(policy) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
`autoFile=${String(policy.autoFile)}${dismiss} (source=${policy.source}).`);
|
|
96
|
+
return (`[deft policy] coverageDebt mode=${policy.mode} ` +
|
|
97
|
+
`autoFile=${String(policy.autoFile)} (source=${policy.source}).`);
|
|
134
98
|
}
|
|
135
99
|
function fieldFromResolved(resolved) {
|
|
136
100
|
return {
|
|
137
101
|
name: FIELD_COVERAGE_DEBT,
|
|
138
102
|
current: {
|
|
139
|
-
status: resolved.status,
|
|
140
103
|
mode: resolved.mode,
|
|
141
104
|
autoFile: resolved.autoFile,
|
|
142
|
-
dismissReason: resolved.dismissReason,
|
|
143
105
|
},
|
|
144
106
|
default: {
|
|
145
|
-
status: "unset",
|
|
146
107
|
mode: DEFAULT_COVERAGE_DEBT_MODE,
|
|
147
108
|
autoFile: DEFAULT_COVERAGE_DEBT_AUTO_FILE,
|
|
148
|
-
dismissReason: null,
|
|
149
109
|
},
|
|
150
110
|
source: resolved.source,
|
|
151
111
|
};
|
|
@@ -167,96 +127,27 @@ export function inspectCoverageDebt(data, projectRoot) {
|
|
|
167
127
|
}
|
|
168
128
|
return fieldFromResolved(resolveCoverageDebtFromTypedBlock(policyBlock.coverageDebt));
|
|
169
129
|
}
|
|
170
|
-
/**
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const data = parsed;
|
|
180
|
-
if (typeof data.plan !== "object" || data.plan === null || Array.isArray(data.plan)) {
|
|
181
|
-
if (data.plan === undefined) {
|
|
182
|
-
data.plan = {};
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
throw new Error("PROJECT-DEFINITION 'plan' is not an object");
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
const plan = data.plan;
|
|
189
|
-
migrateLegacyPolicyKey(plan);
|
|
190
|
-
const existingPolicy = plan[PLAN_POLICY_KEY];
|
|
191
|
-
if (typeof existingPolicy !== "object" ||
|
|
192
|
-
existingPolicy === null ||
|
|
193
|
-
Array.isArray(existingPolicy)) {
|
|
194
|
-
if (existingPolicy === undefined) {
|
|
195
|
-
plan[PLAN_POLICY_KEY] = {};
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
throw new Error("plan.policy is not an object");
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const policyBlock = plan[PLAN_POLICY_KEY];
|
|
202
|
-
const previous = policyBlock.coverageDebt;
|
|
203
|
-
const autoFile = options.mode === "hatch" ? (options.autoFile ?? DEFAULT_COVERAGE_DEBT_AUTO_FILE) : false;
|
|
204
|
-
const dismissReason = typeof options.dismissReason === "string" && options.dismissReason.trim().length > 0
|
|
205
|
-
? options.dismissReason.trim()
|
|
206
|
-
: null;
|
|
207
|
-
const nextBlock = {
|
|
208
|
-
status: "decided",
|
|
209
|
-
mode: options.mode,
|
|
210
|
-
autoFile,
|
|
211
|
-
dismissReason,
|
|
212
|
-
};
|
|
213
|
-
const previousNormalized = resolveCoverageDebtFromTypedBlock(previous);
|
|
214
|
-
const changedFlag = previousNormalized.status !== nextBlock.status ||
|
|
215
|
-
previousNormalized.mode !== nextBlock.mode ||
|
|
216
|
-
previousNormalized.autoFile !== nextBlock.autoFile ||
|
|
217
|
-
previousNormalized.dismissReason !== nextBlock.dismissReason;
|
|
218
|
-
policyBlock.coverageDebt = nextBlock;
|
|
219
|
-
if (changedFlag) {
|
|
220
|
-
atomicWriteProjectDefinition(path, data);
|
|
221
|
-
}
|
|
222
|
-
const actor = options.actor ?? policyColonInvocation("set-coverage-debt");
|
|
223
|
-
const note = options.note ?? "";
|
|
224
|
-
const parts = [
|
|
225
|
-
`actor=${actor}`,
|
|
226
|
-
"coverageDebt.status=decided",
|
|
227
|
-
`mode=${nextBlock.mode}`,
|
|
228
|
-
`autoFile=${String(nextBlock.autoFile)}`,
|
|
229
|
-
`dismissReason=${JSON.stringify(nextBlock.dismissReason)}`,
|
|
230
|
-
`previous=${JSON.stringify(previous ?? null)}`,
|
|
231
|
-
];
|
|
232
|
-
if (note) {
|
|
233
|
-
parts.push(`note=${note.replace(/\n/g, " ").replace(/\r/g, " ")}`);
|
|
234
|
-
}
|
|
235
|
-
appendAuditLog(projectRoot, parts.join(" "));
|
|
236
|
-
return { changed: changedFlag };
|
|
237
|
-
});
|
|
238
|
-
const resolved = resolveCoverageDebt(projectRoot);
|
|
239
|
-
const lines = [
|
|
240
|
-
`\u2713 ${FIELD_COVERAGE_DEBT} status=decided mode=${resolved.mode}.`,
|
|
241
|
-
changed
|
|
242
|
-
? " audit: meta/policy-changes.log updated."
|
|
243
|
-
: " no-op: value already matched (audit entry still appended for trail).",
|
|
244
|
-
formatCoverageDebtStatusLine(resolved),
|
|
245
|
-
];
|
|
246
|
-
return { exitCode: 0, stdout: `${lines.join("\n")}\n`, changed };
|
|
130
|
+
/**
|
|
131
|
+
* One-line standing disclosure when either setting is non-default (#3314).
|
|
132
|
+
* Silent when both default / invalid (invalid is fail-closed off).
|
|
133
|
+
*/
|
|
134
|
+
export function coverageCheckResumeDisclosureLine(debt, resume) {
|
|
135
|
+
const debtNonDefault = debt.source !== "default-on-error" && debt.mode !== DEFAULT_COVERAGE_DEBT_MODE;
|
|
136
|
+
const resumeNonDefault = resume.source !== "default-on-error" && resume.localStamp === "on";
|
|
137
|
+
if (!debtNonDefault && !resumeNonDefault) {
|
|
138
|
+
return null;
|
|
247
139
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
exitCode: 2,
|
|
255
|
-
stdout: `\u274c PROJECT-DEFINITION not found under ${projectRoot}\n`,
|
|
256
|
-
changed: false,
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
return { exitCode: 2, stdout: `\u274c Config error: ${message}\n`, changed: false };
|
|
140
|
+
const parts = [];
|
|
141
|
+
if (debtNonDefault) {
|
|
142
|
+
parts.push(`coverageDebt.mode=${debt.mode}`);
|
|
143
|
+
}
|
|
144
|
+
if (resumeNonDefault) {
|
|
145
|
+
parts.push("checkResume.localStamp=on");
|
|
260
146
|
}
|
|
147
|
+
return `[deft policy] ${parts.join(" ")} (reserved; not a ship gate).`;
|
|
148
|
+
}
|
|
149
|
+
/** Resolve both settings and format the standing disclosure, or null. */
|
|
150
|
+
export function maybeFormatCoverageCheckResumeDisclosure(projectRoot) {
|
|
151
|
+
return coverageCheckResumeDisclosureLine(resolveCoverageDebt(projectRoot), resolveCheckResume(projectRoot));
|
|
261
152
|
}
|
|
262
153
|
//# sourceMappingURL=coverage-debt.js.map
|
package/dist/policy/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export * from "./agents-md-advisory.js";
|
|
|
3
3
|
export * from "./autonomy.js";
|
|
4
4
|
export * from "./capacity.js";
|
|
5
5
|
export * from "./ceremony-dial.js";
|
|
6
|
+
export * from "./ceremony-dial-escalation.js";
|
|
6
7
|
export * from "./check-resume.js";
|
|
7
|
-
export * from "./coverage-check-resume-presets.js";
|
|
8
8
|
export * from "./coverage-debt.js";
|
|
9
9
|
export * from "./decisions.js";
|
|
10
10
|
export * from "./deft-directive-disable.js";
|
package/dist/policy/index.js
CHANGED
|
@@ -22,8 +22,8 @@ export * from "./agents-md-advisory.js";
|
|
|
22
22
|
export * from "./autonomy.js";
|
|
23
23
|
export * from "./capacity.js";
|
|
24
24
|
export * from "./ceremony-dial.js";
|
|
25
|
+
export * from "./ceremony-dial-escalation.js";
|
|
25
26
|
export * from "./check-resume.js";
|
|
26
|
-
export * from "./coverage-check-resume-presets.js";
|
|
27
27
|
export * from "./coverage-debt.js";
|
|
28
28
|
export * from "./decisions.js";
|
|
29
29
|
export * from "./deft-directive-disable.js";
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Interoperates with #3267 plan.metadata.literal_acceptance_commands.
|
|
6
6
|
*/
|
|
7
7
|
import { attachLiteralAcceptanceCommands, readStoredLiteralAcceptanceCommands, } from "../literal-acceptance/index.js";
|
|
8
|
+
import { readAcceptanceClauses, serializeAcceptanceClauses } from "../verify-ac/clauses.js";
|
|
8
9
|
import { PLAN_ACCEPTANCE_KEY, } from "./types.js";
|
|
9
10
|
function asRecord(value) {
|
|
10
11
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
@@ -73,6 +74,22 @@ export function validatePlanAcceptance(value) {
|
|
|
73
74
|
if ("source_rung" in rec && rec.source_rung !== undefined && !isAcSourceRung(rec.source_rung)) {
|
|
74
75
|
errors.push('plan.acceptance.source_rung must be "stated" | "derived" | "project_floor"');
|
|
75
76
|
}
|
|
77
|
+
if ("clauses" in rec && rec.clauses !== undefined && !Array.isArray(rec.clauses)) {
|
|
78
|
+
errors.push("plan.acceptance.clauses must be an array");
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(rec.clauses)) {
|
|
81
|
+
rec.clauses.forEach((entry, index) => {
|
|
82
|
+
const row = asRecord(entry);
|
|
83
|
+
if (row === null) {
|
|
84
|
+
errors.push(`plan.acceptance.clauses[${index}] must be an object`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const text = isNonEmptyString(row.text) ? row.text.trim() : "";
|
|
88
|
+
if (text.length === 0) {
|
|
89
|
+
errors.push(`plan.acceptance.clauses[${index}].text must be a non-empty string`);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
76
93
|
const commands = coerceCommands(rec.commands);
|
|
77
94
|
const noneStated = rec.none_stated === true;
|
|
78
95
|
if (commands.length === 0 && !noneStated) {
|
|
@@ -110,6 +127,7 @@ export function readPlanAcceptance(plan) {
|
|
|
110
127
|
if (noneStated && commands.length === 0) {
|
|
111
128
|
sourceRung = isAcSourceRung(rec.source_rung) ? rec.source_rung : "project_floor";
|
|
112
129
|
}
|
|
130
|
+
const clauses = readAcceptanceClauses(rec);
|
|
113
131
|
return {
|
|
114
132
|
commands,
|
|
115
133
|
none_stated: noneStated,
|
|
@@ -119,6 +137,7 @@ export function readPlanAcceptance(plan) {
|
|
|
119
137
|
: isNonEmptyString(rec.derivedReason)
|
|
120
138
|
? rec.derivedReason
|
|
121
139
|
: null,
|
|
140
|
+
...(clauses.length > 0 ? { clauses } : {}),
|
|
122
141
|
};
|
|
123
142
|
}
|
|
124
143
|
}
|
|
@@ -181,6 +200,9 @@ export function attachPlanAcceptance(plan, acceptance) {
|
|
|
181
200
|
if (acceptance.derived_reason) {
|
|
182
201
|
serializable.derived_reason = acceptance.derived_reason;
|
|
183
202
|
}
|
|
203
|
+
if (acceptance.clauses !== undefined && acceptance.clauses.length > 0) {
|
|
204
|
+
serializable.clauses = serializeAcceptanceClauses(acceptance.clauses);
|
|
205
|
+
}
|
|
184
206
|
let next = {
|
|
185
207
|
...plan,
|
|
186
208
|
[PLAN_ACCEPTANCE_KEY]: serializable,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Empty verify:ac resolution is not a green run when there is no suite floor (#3334).
|
|
3
|
+
*
|
|
4
|
+
* Framework source keeps today's floor-pass (suite gates own the floor).
|
|
5
|
+
* Consumer / no-suite projects fail closed with a distinct soft_empty outcome.
|
|
6
|
+
*/
|
|
7
|
+
import type { PlanAcceptance } from "./types.js";
|
|
8
|
+
export declare const EMPTY_AC_OUTCOME: "soft_empty";
|
|
9
|
+
export declare const EMPTY_AC_CAUSE = "no acceptance stamped \u2014 floor is empty in this project";
|
|
10
|
+
export declare const EMPTY_AC_REMEDY = "stamp plan.acceptance (author commands or run intake capture / task issue:ingest)";
|
|
11
|
+
export type VerifyAcResolution = "verified-pass" | "empty-pass" | "soft_empty" | "fail" | "config" | "skipped";
|
|
12
|
+
/** True when this project check composition includes a suite gate (#3188). */
|
|
13
|
+
export declare function projectHasSuiteFloor(projectRoot: string): boolean;
|
|
14
|
+
export declare function isSoftEmptyAcText(text: string): boolean;
|
|
15
|
+
export interface EmptyAcResolutionInput {
|
|
16
|
+
readonly ok: boolean;
|
|
17
|
+
readonly code: number;
|
|
18
|
+
readonly runsLength: number;
|
|
19
|
+
readonly commandCount: number;
|
|
20
|
+
readonly rejectedCount: number;
|
|
21
|
+
readonly resolution?: VerifyAcResolution;
|
|
22
|
+
}
|
|
23
|
+
/** Zero executable commands, no rejected/unpromoted ledger, not already classified. */
|
|
24
|
+
export declare function isEmptyAcResolution(input: EmptyAcResolutionInput): boolean;
|
|
25
|
+
export declare function formatSoftEmptyMessage(acceptance: PlanAcceptance, quiet?: boolean): string;
|
|
26
|
+
//# sourceMappingURL=empty-resolution.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Empty verify:ac resolution is not a green run when there is no suite floor (#3334).
|
|
3
|
+
*
|
|
4
|
+
* Framework source keeps today's floor-pass (suite gates own the floor).
|
|
5
|
+
* Consumer / no-suite projects fail closed with a distinct soft_empty outcome.
|
|
6
|
+
*/
|
|
7
|
+
import { isFrameworkRepoRoot } from "../check/context.js";
|
|
8
|
+
export const EMPTY_AC_OUTCOME = "soft_empty";
|
|
9
|
+
export const EMPTY_AC_CAUSE = "no acceptance stamped — floor is empty in this project";
|
|
10
|
+
export const EMPTY_AC_REMEDY = "stamp plan.acceptance (author commands or run intake capture / task issue:ingest)";
|
|
11
|
+
/** True when this project check composition includes a suite gate (#3188). */
|
|
12
|
+
export function projectHasSuiteFloor(projectRoot) {
|
|
13
|
+
return isFrameworkRepoRoot(projectRoot);
|
|
14
|
+
}
|
|
15
|
+
export function isSoftEmptyAcText(text) {
|
|
16
|
+
return /soft_empty\s*\(#3334\)/i.test(text);
|
|
17
|
+
}
|
|
18
|
+
/** Zero executable commands, no rejected/unpromoted ledger, not already classified. */
|
|
19
|
+
export function isEmptyAcResolution(input) {
|
|
20
|
+
if (input.resolution === "config" || input.resolution === "skipped") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (input.code === 2) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (input.rejectedCount > 0 || input.commandCount > 0 || input.runsLength > 0) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
export function formatSoftEmptyMessage(acceptance, quiet) {
|
|
32
|
+
if (quiet) {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
return (`verify:ac ${EMPTY_AC_OUTCOME} (#3334) [rung=${acceptance.source_rung}]: ` +
|
|
36
|
+
`${EMPTY_AC_CAUSE}. ${EMPTY_AC_REMEDY}.`);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=empty-resolution.js.map
|
|
@@ -3,15 +3,22 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Runs plan.acceptance.commands (or #3267 literal ledger) via the shared
|
|
5
5
|
* literal-acceptance runner. Records source_rung in the result message.
|
|
6
|
-
* Project floor with empty commands is a soft pass
|
|
7
|
-
* inside full `task check`)
|
|
6
|
+
* Project floor with empty commands is a soft pass only when a suite floor
|
|
7
|
+
* exists (suite gates own the floor inside full `task check`). With no suite
|
|
8
|
+
* floor, empty resolution is soft_empty — not a green run (#3334).
|
|
8
9
|
*/
|
|
9
10
|
import { type EvaluateLiteralAcceptanceOptions, type LiteralAcceptanceGateResult } from "../literal-acceptance/index.js";
|
|
11
|
+
import { type ClauseWalkResult } from "../verify-ac/clauses.js";
|
|
12
|
+
import { type VerifyAcResolution } from "./empty-resolution.js";
|
|
10
13
|
import type { AcSourceRung, PlanAcceptance } from "./types.js";
|
|
11
14
|
export interface VerifyAcResult extends LiteralAcceptanceGateResult {
|
|
12
15
|
readonly sourceRung: AcSourceRung;
|
|
13
16
|
readonly noneStated: boolean;
|
|
14
17
|
readonly acceptance: PlanAcceptance;
|
|
18
|
+
readonly resolution: VerifyAcResolution;
|
|
19
|
+
readonly resolvedCommandCount: number;
|
|
20
|
+
readonly clauseOutcomes?: readonly ClauseWalkResult[];
|
|
21
|
+
readonly clauseWalked?: boolean;
|
|
15
22
|
}
|
|
16
23
|
export interface EvaluateVerifyAcOptions extends EvaluateLiteralAcceptanceOptions {
|
|
17
24
|
/**
|
|
@@ -36,6 +43,31 @@ export interface EvaluateVerifyAcOptions extends EvaluateLiteralAcceptanceOption
|
|
|
36
43
|
readonly bankOnPass?: boolean;
|
|
37
44
|
/** Optional scope id override for the bank ledger (default plan.id / path). */
|
|
38
45
|
readonly bankScopeId?: string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Injected run-summary JSONL for product-oracle integrity (#3322).
|
|
48
|
+
* Undefined → read DEFT_RUN_SUMMARY_PATH / default dest; null → skip disk.
|
|
49
|
+
*/
|
|
50
|
+
readonly runSummaryText?: string | null;
|
|
51
|
+
/** When false, skip #3322 oracle integrity. Default true. */
|
|
52
|
+
readonly applyOracleIntegrity?: boolean;
|
|
53
|
+
/** Env seam for run-summary dest resolution (#3322 / #3334). */
|
|
54
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
55
|
+
/**
|
|
56
|
+
* Inject suite-floor detection (tests). Default: framework source has a
|
|
57
|
+
* suite floor; consumer projects do not (#3334).
|
|
58
|
+
*/
|
|
59
|
+
readonly hasSuiteFloor?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* When true, skip the acceptance run-summary emit so the path helper can
|
|
62
|
+
* emit after the #3285 bank checkpoint.
|
|
63
|
+
*/
|
|
64
|
+
readonly skipAcceptanceEmit?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Active scope key for product-oracle check_id namespacing (#3337).
|
|
67
|
+
* Prefer plan.id; path stem when id is missing. Multi-active verify:ac
|
|
68
|
+
* under one session must not share a single global `verify:ac` check id.
|
|
69
|
+
*/
|
|
70
|
+
readonly oracleScopeKey?: string | null;
|
|
39
71
|
}
|
|
40
72
|
/**
|
|
41
73
|
* Evaluate product AC from an in-memory plan.
|
|
@@ -45,6 +77,12 @@ export declare function evaluateVerifyAcFromPlan(plan: Record<string, unknown>,
|
|
|
45
77
|
* Evaluate from xBRIEF path.
|
|
46
78
|
*/
|
|
47
79
|
export declare function evaluateVerifyAcFromPath(xbriefPath: string, options?: EvaluateVerifyAcOptions): VerifyAcResult;
|
|
80
|
+
/**
|
|
81
|
+
* Unique product-oracle scope key for one active xBRIEF path (#3337).
|
|
82
|
+
* Relative path is always unique across active roots; plan.id alone is not
|
|
83
|
+
* (duplicate ids / same stem in xbrief+vbrief). Prefer `id@relPath` when both exist.
|
|
84
|
+
*/
|
|
85
|
+
export declare function resolveOracleScopeKey(plan: Record<string, unknown>, xbriefPath: string, projectRoot: string): string;
|
|
48
86
|
/** Pure: product AC is required at every ceremony depth (#3284 / #3267 / #3156). */
|
|
49
87
|
export declare function isVerifyAcRequiredAtCeremonyDepth(_depth: string | null | undefined): boolean;
|
|
50
88
|
//# sourceMappingURL=evaluate.d.ts.map
|