@deftai/directive-core 0.101.0 → 0.102.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/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 +28 -2
- package/dist/product-first-done-gate/evaluate.js +209 -53
- package/dist/product-first-done-gate/index.d.ts +1 -0
- package/dist/product-first-done-gate/index.js +1 -0
- 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 +55 -0
- package/dist/verify-ac/evaluate.js +145 -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,45 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Check-resume / local suite-stamp policy (#3189).
|
|
2
|
+
* Check-resume / local suite-stamp policy (#3189 / #3314).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* stamp in v1 — `ciTrustsLocalStamp` is fixed false.
|
|
4
|
+
* Plain optional setting. Default off. Fail-closed when absent or invalid.
|
|
5
|
+
* Reserved — consumer expansion not implemented. CI never trusts a laptop stamp.
|
|
7
6
|
*/
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { migrateLegacyPolicyKey, PLAN_POLICY_KEY, readPlanPolicy } from "./plan-extensions.js";
|
|
11
|
-
import { policyColonInvocation } from "./policy-invocation.js";
|
|
12
|
-
import { appendAuditLog, loadProjectDefinition, projectDefinitionPath } from "./resolve.js";
|
|
7
|
+
import { readPlanPolicy } from "./plan-extensions.js";
|
|
8
|
+
import { loadProjectDefinition } from "./resolve.js";
|
|
13
9
|
/** Canonical registered policy field name. */
|
|
14
10
|
export const FIELD_CHECK_RESUME = "plan.policy.checkResume";
|
|
15
11
|
/** Short alias for `policy:show --field=checkResume`. */
|
|
16
12
|
export const FIELD_CHECK_RESUME_CLI_ALIAS = "checkResume";
|
|
17
|
-
export const CHECK_RESUME_STATUSES = ["unset", "decided"];
|
|
18
13
|
export const CHECK_RESUME_LOCAL_STAMP = ["off", "on"];
|
|
19
|
-
/** Fail-closed when
|
|
14
|
+
/** Fail-closed when absent / missing / invalid. */
|
|
20
15
|
export const DEFAULT_CHECK_RESUME_LOCAL_STAMP = "off";
|
|
21
|
-
/**
|
|
22
|
-
* FIXED false in v1 (#3189 non-goal). Separate RFC required to ever allow CI
|
|
23
|
-
* to trust a laptop suite stamp.
|
|
24
|
-
*/
|
|
25
|
-
export const CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1 = false;
|
|
26
16
|
function defaultResolved(source, error = null) {
|
|
27
17
|
return {
|
|
28
|
-
status: "unset",
|
|
29
18
|
localStamp: DEFAULT_CHECK_RESUME_LOCAL_STAMP,
|
|
30
|
-
ciTrustsLocalStamp: CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1,
|
|
31
|
-
dismissReason: null,
|
|
32
19
|
source,
|
|
33
20
|
error,
|
|
34
21
|
};
|
|
35
22
|
}
|
|
36
|
-
function isStatus(value) {
|
|
37
|
-
return typeof value === "string" && CHECK_RESUME_STATUSES.includes(value);
|
|
38
|
-
}
|
|
39
23
|
function isLocalStamp(value) {
|
|
40
24
|
return (typeof value === "string" && CHECK_RESUME_LOCAL_STAMP.includes(value));
|
|
41
25
|
}
|
|
42
|
-
/** Validate a `plan.policy.checkResume` payload. */
|
|
26
|
+
/** Validate a `plan.policy.checkResume` payload. Extra keys are ignored. */
|
|
43
27
|
export function validateCheckResume(value) {
|
|
44
28
|
if (value === null || value === undefined) {
|
|
45
29
|
return [];
|
|
@@ -48,27 +32,16 @@ export function validateCheckResume(value) {
|
|
|
48
32
|
return [`${FIELD_CHECK_RESUME} must be an object; got ${typeof value}`];
|
|
49
33
|
}
|
|
50
34
|
const rec = value;
|
|
51
|
-
const errors = [];
|
|
52
|
-
if ("status" in rec && !isStatus(rec.status)) {
|
|
53
|
-
errors.push(`${FIELD_CHECK_RESUME}.status must be one of ${CHECK_RESUME_STATUSES.join("|")}`);
|
|
54
|
-
}
|
|
55
35
|
if ("localStamp" in rec && !isLocalStamp(rec.localStamp)) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
errors.push(`${FIELD_CHECK_RESUME}.ciTrustsLocalStamp must be false in v1 (CI never trusts local stamps)`);
|
|
60
|
-
}
|
|
61
|
-
if ("dismissReason" in rec &&
|
|
62
|
-
rec.dismissReason !== null &&
|
|
63
|
-
typeof rec.dismissReason !== "string") {
|
|
64
|
-
errors.push(`${FIELD_CHECK_RESUME}.dismissReason must be a string or null`);
|
|
36
|
+
return [
|
|
37
|
+
`${FIELD_CHECK_RESUME}.localStamp must be one of ${CHECK_RESUME_LOCAL_STAMP.join("|")}`,
|
|
38
|
+
];
|
|
65
39
|
}
|
|
66
|
-
return
|
|
40
|
+
return [];
|
|
67
41
|
}
|
|
68
42
|
/**
|
|
69
|
-
* Resolve a typed block. Missing/invalid → localStamp off
|
|
70
|
-
*
|
|
71
|
-
* (malformed non-false is validation error → fail-closed default).
|
|
43
|
+
* Resolve a typed block. Missing/invalid → localStamp off.
|
|
44
|
+
* Leftover ritual fields (status/dismissReason/ciTrustsLocalStamp) are ignored.
|
|
72
45
|
*/
|
|
73
46
|
export function resolveCheckResumeFromTypedBlock(raw) {
|
|
74
47
|
const errors = validateCheckResume(raw);
|
|
@@ -79,25 +52,16 @@ export function resolveCheckResumeFromTypedBlock(raw) {
|
|
|
79
52
|
return defaultResolved("default");
|
|
80
53
|
}
|
|
81
54
|
const block = raw;
|
|
82
|
-
const
|
|
83
|
-
const localStampRaw = isLocalStamp(block.localStamp)
|
|
55
|
+
const localStamp = isLocalStamp(block.localStamp)
|
|
84
56
|
? block.localStamp
|
|
85
57
|
: DEFAULT_CHECK_RESUME_LOCAL_STAMP;
|
|
86
|
-
// Fail-closed: local stamp only when decided.
|
|
87
|
-
const localStamp = status === "decided" ? localStampRaw : DEFAULT_CHECK_RESUME_LOCAL_STAMP;
|
|
88
|
-
const dismissReason = typeof block.dismissReason === "string" && block.dismissReason.trim().length > 0
|
|
89
|
-
? block.dismissReason.trim()
|
|
90
|
-
: null;
|
|
91
58
|
return {
|
|
92
|
-
status,
|
|
93
59
|
localStamp,
|
|
94
|
-
ciTrustsLocalStamp: CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1,
|
|
95
|
-
dismissReason: status === "decided" ? dismissReason : null,
|
|
96
60
|
source: "typed",
|
|
97
61
|
error: null,
|
|
98
62
|
};
|
|
99
63
|
}
|
|
100
|
-
/** Resolve `plan.policy.checkResume` from PROJECT-DEFINITION (#
|
|
64
|
+
/** Resolve `plan.policy.checkResume` from PROJECT-DEFINITION (#3314). */
|
|
101
65
|
export function resolveCheckResume(projectRoot) {
|
|
102
66
|
const [data, err] = loadProjectDefinition(projectRoot);
|
|
103
67
|
if (data === null) {
|
|
@@ -112,33 +76,21 @@ export function resolveCheckResume(projectRoot) {
|
|
|
112
76
|
}
|
|
113
77
|
return resolveCheckResumeFromTypedBlock(policyBlock.checkResume);
|
|
114
78
|
}
|
|
115
|
-
/** Local suite stamp resume only when
|
|
79
|
+
/** Local suite stamp resume only when localStamp=on. Reserved — unused by check/release. */
|
|
116
80
|
export function isLocalStampResumeAllowed(policy) {
|
|
117
|
-
return policy.
|
|
118
|
-
}
|
|
119
|
-
/** Always false in v1 — CI must re-run suite, never trust a laptop stamp. */
|
|
120
|
-
export function isCiTrustsLocalStampAllowed(_policy) {
|
|
121
|
-
return CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1;
|
|
81
|
+
return policy.localStamp === "on";
|
|
122
82
|
}
|
|
123
83
|
export function formatCheckResumeStatusLine(policy) {
|
|
124
|
-
|
|
125
|
-
return (`[deft policy] checkResume status=${policy.status} localStamp=${policy.localStamp} ` +
|
|
126
|
-
`ciTrustsLocalStamp=${String(policy.ciTrustsLocalStamp)}${dismiss} (source=${policy.source}).`);
|
|
84
|
+
return (`[deft policy] checkResume localStamp=${policy.localStamp} ` + `(source=${policy.source}).`);
|
|
127
85
|
}
|
|
128
86
|
function fieldFromResolved(resolved) {
|
|
129
87
|
return {
|
|
130
88
|
name: FIELD_CHECK_RESUME,
|
|
131
89
|
current: {
|
|
132
|
-
status: resolved.status,
|
|
133
90
|
localStamp: resolved.localStamp,
|
|
134
|
-
ciTrustsLocalStamp: CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1,
|
|
135
|
-
dismissReason: resolved.dismissReason,
|
|
136
91
|
},
|
|
137
92
|
default: {
|
|
138
|
-
status: "unset",
|
|
139
93
|
localStamp: DEFAULT_CHECK_RESUME_LOCAL_STAMP,
|
|
140
|
-
ciTrustsLocalStamp: CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1,
|
|
141
|
-
dismissReason: null,
|
|
142
94
|
},
|
|
143
95
|
source: resolved.source,
|
|
144
96
|
};
|
|
@@ -160,94 +112,4 @@ export function inspectCheckResume(data, projectRoot) {
|
|
|
160
112
|
}
|
|
161
113
|
return fieldFromResolved(resolveCheckResumeFromTypedBlock(policyBlock.checkResume));
|
|
162
114
|
}
|
|
163
|
-
/** Persist decided checkResume (preset or dismiss-with-reason). */
|
|
164
|
-
export function writeCheckResume(projectRoot, options) {
|
|
165
|
-
const path = projectDefinitionPath(projectRoot);
|
|
166
|
-
try {
|
|
167
|
-
const { changed } = projectDefinitionMutationLock(projectRoot, () => {
|
|
168
|
-
const parsed = JSON.parse(readFileSync(path, { encoding: "utf8" }));
|
|
169
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
170
|
-
throw new Error(`PROJECT-DEFINITION at ${path} top-level value is not a JSON object`);
|
|
171
|
-
}
|
|
172
|
-
const data = parsed;
|
|
173
|
-
if (typeof data.plan !== "object" || data.plan === null || Array.isArray(data.plan)) {
|
|
174
|
-
if (data.plan === undefined) {
|
|
175
|
-
data.plan = {};
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
throw new Error("PROJECT-DEFINITION 'plan' is not an object");
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const plan = data.plan;
|
|
182
|
-
migrateLegacyPolicyKey(plan);
|
|
183
|
-
const existingPolicy = plan[PLAN_POLICY_KEY];
|
|
184
|
-
if (typeof existingPolicy !== "object" ||
|
|
185
|
-
existingPolicy === null ||
|
|
186
|
-
Array.isArray(existingPolicy)) {
|
|
187
|
-
if (existingPolicy === undefined) {
|
|
188
|
-
plan[PLAN_POLICY_KEY] = {};
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
throw new Error("plan.policy is not an object");
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
const policyBlock = plan[PLAN_POLICY_KEY];
|
|
195
|
-
const previous = policyBlock.checkResume;
|
|
196
|
-
const dismissReason = typeof options.dismissReason === "string" && options.dismissReason.trim().length > 0
|
|
197
|
-
? options.dismissReason.trim()
|
|
198
|
-
: null;
|
|
199
|
-
const nextBlock = {
|
|
200
|
-
status: "decided",
|
|
201
|
-
localStamp: options.localStamp,
|
|
202
|
-
ciTrustsLocalStamp: CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1,
|
|
203
|
-
dismissReason,
|
|
204
|
-
};
|
|
205
|
-
const previousNormalized = resolveCheckResumeFromTypedBlock(previous);
|
|
206
|
-
const changedFlag = previousNormalized.status !== nextBlock.status ||
|
|
207
|
-
previousNormalized.localStamp !== nextBlock.localStamp ||
|
|
208
|
-
previousNormalized.dismissReason !== nextBlock.dismissReason;
|
|
209
|
-
policyBlock.checkResume = nextBlock;
|
|
210
|
-
if (changedFlag) {
|
|
211
|
-
atomicWriteProjectDefinition(path, data);
|
|
212
|
-
}
|
|
213
|
-
const actor = options.actor ?? policyColonInvocation("set-check-resume");
|
|
214
|
-
const note = options.note ?? "";
|
|
215
|
-
const parts = [
|
|
216
|
-
`actor=${actor}`,
|
|
217
|
-
"checkResume.status=decided",
|
|
218
|
-
`localStamp=${nextBlock.localStamp}`,
|
|
219
|
-
"ciTrustsLocalStamp=false",
|
|
220
|
-
`dismissReason=${JSON.stringify(nextBlock.dismissReason)}`,
|
|
221
|
-
`previous=${JSON.stringify(previous ?? null)}`,
|
|
222
|
-
];
|
|
223
|
-
if (note) {
|
|
224
|
-
parts.push(`note=${note.replace(/\n/g, " ").replace(/\r/g, " ")}`);
|
|
225
|
-
}
|
|
226
|
-
appendAuditLog(projectRoot, parts.join(" "));
|
|
227
|
-
return { changed: changedFlag };
|
|
228
|
-
});
|
|
229
|
-
const resolved = resolveCheckResume(projectRoot);
|
|
230
|
-
const lines = [
|
|
231
|
-
`\u2713 ${FIELD_CHECK_RESUME} status=decided localStamp=${resolved.localStamp}.`,
|
|
232
|
-
changed
|
|
233
|
-
? " audit: meta/policy-changes.log updated."
|
|
234
|
-
: " no-op: value already matched (audit entry still appended for trail).",
|
|
235
|
-
formatCheckResumeStatusLine(resolved),
|
|
236
|
-
];
|
|
237
|
-
return { exitCode: 0, stdout: `${lines.join("\n")}\n`, changed };
|
|
238
|
-
}
|
|
239
|
-
catch (err) {
|
|
240
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
241
|
-
if (message.includes("PROJECT-DEFINITION not found") ||
|
|
242
|
-
message.includes("ENOENT") ||
|
|
243
|
-
message.includes("no such file")) {
|
|
244
|
-
return {
|
|
245
|
-
exitCode: 2,
|
|
246
|
-
stdout: `\u274c PROJECT-DEFINITION not found under ${projectRoot}\n`,
|
|
247
|
-
changed: false,
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
return { exitCode: 2, stdout: `\u274c Config error: ${message}\n`, changed: false };
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
115
|
//# sourceMappingURL=check-resume.js.map
|
|
@@ -1,55 +1,43 @@
|
|
|
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
|
*/
|
|
8
|
+
import { type CheckResumeResolved } from "./check-resume.js";
|
|
11
9
|
/** Canonical registered policy field name. */
|
|
12
10
|
export declare const FIELD_COVERAGE_DEBT = "plan.policy.coverageDebt";
|
|
13
11
|
/** Short alias for `policy:show --field=coverageDebt`. */
|
|
14
12
|
export declare const FIELD_COVERAGE_DEBT_CLI_ALIAS = "coverageDebt";
|
|
15
|
-
export declare const COVERAGE_DEBT_STATUSES: readonly ["unset", "decided"];
|
|
16
|
-
export type CoverageDebtStatus = (typeof COVERAGE_DEBT_STATUSES)[number];
|
|
17
13
|
export declare const COVERAGE_DEBT_MODES: readonly ["off", "warn", "hatch"];
|
|
18
14
|
export type CoverageDebtMode = (typeof COVERAGE_DEBT_MODES)[number];
|
|
19
|
-
/** Fail-closed effective mode when
|
|
15
|
+
/** Fail-closed effective mode when absent / missing / invalid. */
|
|
20
16
|
export declare const DEFAULT_COVERAGE_DEBT_MODE: CoverageDebtMode;
|
|
21
17
|
/** Consumers default autoFile false even under hatch mode. */
|
|
22
18
|
export declare const DEFAULT_COVERAGE_DEBT_AUTO_FILE = false;
|
|
23
19
|
export interface CoverageDebtConfig {
|
|
24
|
-
readonly status: CoverageDebtStatus;
|
|
25
20
|
readonly mode: CoverageDebtMode;
|
|
26
21
|
readonly autoFile: boolean;
|
|
27
|
-
/** Present when decided via dismiss-with-reason (still visible to show/doctor). */
|
|
28
|
-
readonly dismissReason: string | null;
|
|
29
22
|
}
|
|
30
23
|
export type CoverageDebtSource = "typed" | "default" | "default-on-error";
|
|
31
24
|
export interface CoverageDebtResolved extends CoverageDebtConfig {
|
|
32
25
|
readonly source: CoverageDebtSource;
|
|
33
26
|
readonly error: string | null;
|
|
34
27
|
}
|
|
35
|
-
/** Validate a `plan.policy.coverageDebt` payload. */
|
|
28
|
+
/** Validate a `plan.policy.coverageDebt` payload. Extra keys are ignored. */
|
|
36
29
|
export declare function validateCoverageDebt(value: unknown): string[];
|
|
37
30
|
/**
|
|
38
|
-
* Resolve a typed block. Missing/invalid → fail-closed mode off
|
|
39
|
-
*
|
|
31
|
+
* Resolve a typed block. Missing/invalid → fail-closed mode off.
|
|
32
|
+
* `mode` is the setting; leftover ritual fields (status/dismissReason) are ignored.
|
|
40
33
|
*/
|
|
41
34
|
export declare function resolveCoverageDebtFromTypedBlock(raw: unknown): CoverageDebtResolved;
|
|
42
|
-
/** Resolve `plan.policy.coverageDebt` from PROJECT-DEFINITION (#
|
|
35
|
+
/** Resolve `plan.policy.coverageDebt` from PROJECT-DEFINITION (#3314). */
|
|
43
36
|
export declare function resolveCoverageDebt(projectRoot: string): CoverageDebtResolved;
|
|
44
|
-
/** Effective hatch soft-pass allowed only when
|
|
37
|
+
/** Effective hatch soft-pass allowed only when mode=hatch. Reserved — unused by check/release. */
|
|
45
38
|
export declare function isCoverageDebtHatchAllowed(policy: CoverageDebtResolved): boolean;
|
|
46
39
|
/** Auto-file debt issues only when hatch is allowed AND autoFile true. */
|
|
47
40
|
export declare function isCoverageDebtAutoFileAllowed(policy: CoverageDebtResolved): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Non-goal guard (#3189): consumer trees never auto-file coverage-debt on
|
|
50
|
-
* deftai/directive. Ledger is always the project under check.
|
|
51
|
-
*/
|
|
52
|
-
export declare function coverageDebtLedgerRepoIsSelfOnly(): true;
|
|
53
41
|
export declare function formatCoverageDebtStatusLine(policy: CoverageDebtResolved): string;
|
|
54
42
|
export interface CoverageDebtPolicyField {
|
|
55
43
|
readonly name: typeof FIELD_COVERAGE_DEBT;
|
|
@@ -59,18 +47,11 @@ export interface CoverageDebtPolicyField {
|
|
|
59
47
|
}
|
|
60
48
|
/** Inspector row for `policy:show --field=coverageDebt`. */
|
|
61
49
|
export declare function inspectCoverageDebt(data: Record<string, unknown> | null, projectRoot?: string): CoverageDebtPolicyField;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
export interface WriteCoverageDebtResult {
|
|
70
|
-
readonly exitCode: 0 | 2;
|
|
71
|
-
readonly stdout: string;
|
|
72
|
-
readonly changed: boolean;
|
|
73
|
-
}
|
|
74
|
-
/** Persist decided coverageDebt (preset or dismiss-with-reason). */
|
|
75
|
-
export declare function writeCoverageDebt(projectRoot: string, options: WriteCoverageDebtOptions): WriteCoverageDebtResult;
|
|
50
|
+
/**
|
|
51
|
+
* One-line standing disclosure when either setting is non-default (#3314).
|
|
52
|
+
* Silent when both default / invalid (invalid is fail-closed off).
|
|
53
|
+
*/
|
|
54
|
+
export declare function coverageCheckResumeDisclosureLine(debt: CoverageDebtResolved, resume: Pick<CheckResumeResolved, "localStamp" | "source">): string | null;
|
|
55
|
+
/** Resolve both settings and format the standing disclosure, or null. */
|
|
56
|
+
export declare function maybeFormatCoverageCheckResumeDisclosure(projectRoot: string): string | null;
|
|
76
57
|
//# sourceMappingURL=coverage-debt.d.ts.map
|
|
@@ -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";
|