@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.
Files changed (75) hide show
  1. package/dist/authz/classify.js +97 -8
  2. package/dist/check/cached-orchestrator.d.ts +4 -0
  3. package/dist/check/cached-orchestrator.js +70 -5
  4. package/dist/check/cli-native-gates.d.ts +43 -0
  5. package/dist/check/cli-native-gates.js +84 -0
  6. package/dist/check/index.d.ts +1 -0
  7. package/dist/check/index.js +1 -0
  8. package/dist/check/named-cause.js +10 -0
  9. package/dist/doctor/checks.d.ts +5 -6
  10. package/dist/doctor/checks.js +13 -56
  11. package/dist/eval/later-graduation.d.ts +39 -0
  12. package/dist/eval/later-graduation.js +91 -0
  13. package/dist/eval/report.d.ts +6 -0
  14. package/dist/eval/report.js +27 -8
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +1 -0
  17. package/dist/init-deposit/hygiene.d.ts +7 -1
  18. package/dist/init-deposit/hygiene.js +11 -3
  19. package/dist/init-deposit/scaffold.d.ts +12 -0
  20. package/dist/init-deposit/scaffold.js +81 -8
  21. package/dist/intake/issue-ingest.js +42 -0
  22. package/dist/policy/ceremony-dial-escalation.d.ts +52 -0
  23. package/dist/policy/ceremony-dial-escalation.js +92 -0
  24. package/dist/policy/ceremony-dial.d.ts +3 -1
  25. package/dist/policy/ceremony-dial.js +52 -1
  26. package/dist/policy/check-resume.d.ts +9 -38
  27. package/dist/policy/check-resume.js +18 -156
  28. package/dist/policy/coverage-debt.d.ts +18 -37
  29. package/dist/policy/coverage-debt.js +38 -147
  30. package/dist/policy/index.d.ts +1 -1
  31. package/dist/policy/index.js +1 -1
  32. package/dist/product-first-done-gate/acceptance.js +22 -0
  33. package/dist/product-first-done-gate/empty-resolution.d.ts +26 -0
  34. package/dist/product-first-done-gate/empty-resolution.js +38 -0
  35. package/dist/product-first-done-gate/evaluate.d.ts +40 -2
  36. package/dist/product-first-done-gate/evaluate.js +253 -61
  37. package/dist/product-first-done-gate/index.d.ts +2 -1
  38. package/dist/product-first-done-gate/index.js +2 -1
  39. package/dist/product-first-done-gate/types.d.ts +3 -0
  40. package/dist/product-first-done-gate/types.js +0 -7
  41. package/dist/run-summary/emit.d.ts +11 -1
  42. package/dist/run-summary/emit.js +48 -2
  43. package/dist/run-summary/index.d.ts +2 -1
  44. package/dist/run-summary/index.js +2 -1
  45. package/dist/run-summary/path.d.ts +1 -1
  46. package/dist/run-summary/path.js +1 -1
  47. package/dist/run-summary/share.d.ts +25 -0
  48. package/dist/run-summary/share.js +106 -0
  49. package/dist/run-summary/types.d.ts +60 -2
  50. package/dist/run-summary/types.js +7 -0
  51. package/dist/scope/acceptance-activate-gate.d.ts +23 -0
  52. package/dist/scope/acceptance-activate-gate.js +70 -0
  53. package/dist/scope/index.d.ts +1 -0
  54. package/dist/scope/index.js +1 -0
  55. package/dist/scope/transition.js +5 -0
  56. package/dist/session/index.d.ts +0 -1
  57. package/dist/session/index.js +0 -1
  58. package/dist/session/orientation-compression.js +19 -9
  59. package/dist/session/session-start.d.ts +6 -0
  60. package/dist/session/session-start.js +44 -22
  61. package/dist/session/toolchain-preflight.d.ts +15 -0
  62. package/dist/session/toolchain-preflight.js +65 -5
  63. package/dist/verify-ac/clauses.d.ts +51 -0
  64. package/dist/verify-ac/clauses.js +490 -0
  65. package/dist/verify-ac/evaluate.d.ts +73 -0
  66. package/dist/verify-ac/evaluate.js +167 -0
  67. package/dist/verify-ac/flag.d.ts +35 -0
  68. package/dist/verify-ac/flag.js +104 -0
  69. package/dist/verify-ac/index.d.ts +10 -0
  70. package/dist/verify-ac/index.js +10 -0
  71. package/package.json +7 -3
  72. package/dist/policy/coverage-check-resume-presets.d.ts +0 -46
  73. package/dist/policy/coverage-check-resume-presets.js +0 -228
  74. package/dist/session/coverage-check-resume-nudge.d.ts +0 -34
  75. package/dist/session/coverage-check-resume-nudge.js +0 -66
@@ -401,7 +401,7 @@ export function resolveCeremonyDial(projectRoot, options = {}) {
401
401
  return selected;
402
402
  }
403
403
  /** Human-readable status line for session:start / policy:show. */
404
- export function formatCeremonyDialStatusLine(selection) {
404
+ export function formatCeremonyDialStatusLine(selection, extras) {
405
405
  const parts = [
406
406
  `[deft ceremony-dial] depth=${selection.depth}`,
407
407
  `source=${selection.source}`,
@@ -409,6 +409,10 @@ export function formatCeremonyDialStatusLine(selection) {
409
409
  `modelTier=${selection.inputs.modelTier ?? "-"}`,
410
410
  `projectShape=${selection.inputs.projectShape ?? "-"}`,
411
411
  ];
412
+ if (extras?.startTierProvenance !== undefined && extras.startTierProvenance.length > 0) {
413
+ parts.push(`start-tier=${selection.depth}`);
414
+ parts.push(`provenance=${extras.startTierProvenance}`);
415
+ }
412
416
  if (selection.composition.rapidStrategy) {
413
417
  parts.push(`compose=${selection.composition.rapidStrategy}`);
414
418
  }
@@ -981,7 +985,49 @@ export function formatCeremonyDialAuditLine(audit) {
981
985
  export function escalateCeremonyDial(projectRoot, options) {
982
986
  const prior = resolveCeremonyDial(projectRoot);
983
987
  const from = prior.depth;
988
+ const emitEscalationEvaluation = (applied, reasonSuffix) => {
989
+ if (options.emitRunSummary === false) {
990
+ return;
991
+ }
992
+ try {
993
+ const audit = readCeremonyDialAudit(projectRoot);
994
+ const rawSid = audit.raw?.session_id;
995
+ const sid = options.sessionId ??
996
+ (typeof rawSid === "string" && rawSid.length > 0
997
+ ? rawSid
998
+ : `dial-${Date.now().toString(36)}`);
999
+ const rank = {
1000
+ minimal: 0,
1001
+ rapid: 1,
1002
+ standard: 2,
1003
+ elevated: 3,
1004
+ };
1005
+ const raised = rank[options.to] > rank[from];
1006
+ const outcome = applied && raised ? "escalated" : "declined";
1007
+ const baseReason = options.confirm === true
1008
+ ? options.reason
1009
+ : `${options.reason}; not applied (need --confirm)`;
1010
+ const reason = reasonSuffix !== undefined && reasonSuffix.length > 0
1011
+ ? `${baseReason}; ${reasonSuffix}`
1012
+ : baseReason;
1013
+ const emitter = new RunSummaryEmitter({
1014
+ projectRoot,
1015
+ sessionId: sid,
1016
+ env: options.env,
1017
+ });
1018
+ emitter.emitDialEscalationEvaluation({
1019
+ tier: outcome === "escalated" ? options.to : from,
1020
+ outcome,
1021
+ reason,
1022
+ });
1023
+ emitter.emitKnownToolTurnDenominator();
1024
+ }
1025
+ catch {
1026
+ // fail-open
1027
+ }
1028
+ };
984
1029
  if (options.confirm !== true) {
1030
+ emitEscalationEvaluation(false);
985
1031
  return {
986
1032
  exitCode: 1,
987
1033
  from,
@@ -1001,6 +1047,8 @@ export function escalateCeremonyDial(projectRoot, options) {
1001
1047
  note: options.note ?? `escalate: ${options.reason}`,
1002
1048
  });
1003
1049
  if (setResult.exitCode !== 0) {
1050
+ const persistDetail = oneLineAuditToken(setResult.stdout.trim().split("\n")[0] ?? `exit ${setResult.exitCode}`);
1051
+ emitEscalationEvaluation(false, `persist failed (exit ${setResult.exitCode}): ${persistDetail}`);
1004
1052
  return {
1005
1053
  exitCode: setResult.exitCode,
1006
1054
  from,
@@ -1012,6 +1060,8 @@ export function escalateCeremonyDial(projectRoot, options) {
1012
1060
  .filter((l) => l.length > 0),
1013
1061
  };
1014
1062
  }
1063
+ // #3319: evaluation event on every escalate path (applied or not).
1064
+ emitEscalationEvaluation(true);
1015
1065
  // #3282: event-driven dial_transition line (fail-open).
1016
1066
  if (options.emitRunSummary !== false) {
1017
1067
  try {
@@ -1032,6 +1082,7 @@ export function escalateCeremonyDial(projectRoot, options) {
1032
1082
  reason: options.reason,
1033
1083
  evidence: options.evidence,
1034
1084
  });
1085
+ emitter.emitKnownToolTurnDenominator();
1035
1086
  }
1036
1087
  catch {
1037
1088
  // fail-open
@@ -1,52 +1,36 @@
1
1
  /**
2
- * Check-resume / local suite-stamp policy (#3189).
2
+ * Check-resume / local suite-stamp policy (#3189 / #3314).
3
3
  *
4
- * Consent / SoT surface for consumer expansion of local suite-stamp resume
5
- * (#3188). Unset is fail-closed (localStamp off). CI never trusts a local
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
7
  /** Canonical registered policy field name. */
9
8
  export declare const FIELD_CHECK_RESUME = "plan.policy.checkResume";
10
9
  /** Short alias for `policy:show --field=checkResume`. */
11
10
  export declare const FIELD_CHECK_RESUME_CLI_ALIAS = "checkResume";
12
- export declare const CHECK_RESUME_STATUSES: readonly ["unset", "decided"];
13
- export type CheckResumeStatus = (typeof CHECK_RESUME_STATUSES)[number];
14
11
  export declare const CHECK_RESUME_LOCAL_STAMP: readonly ["off", "on"];
15
12
  export type CheckResumeLocalStamp = (typeof CHECK_RESUME_LOCAL_STAMP)[number];
16
- /** Fail-closed when unset / missing. */
13
+ /** Fail-closed when absent / missing / invalid. */
17
14
  export declare const DEFAULT_CHECK_RESUME_LOCAL_STAMP: CheckResumeLocalStamp;
18
- /**
19
- * FIXED false in v1 (#3189 non-goal). Separate RFC required to ever allow CI
20
- * to trust a laptop suite stamp.
21
- */
22
- export declare const CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1: false;
23
15
  export interface CheckResumeConfig {
24
- readonly status: CheckResumeStatus;
25
16
  readonly localStamp: CheckResumeLocalStamp;
26
- /** Always false in v1; present for schema visibility. */
27
- readonly ciTrustsLocalStamp: false;
28
- /** Present when decided via dismiss-with-reason. */
29
- readonly dismissReason: string | null;
30
17
  }
31
18
  export type CheckResumeSource = "typed" | "default" | "default-on-error";
32
19
  export interface CheckResumeResolved extends CheckResumeConfig {
33
20
  readonly source: CheckResumeSource;
34
21
  readonly error: string | null;
35
22
  }
36
- /** Validate a `plan.policy.checkResume` payload. */
23
+ /** Validate a `plan.policy.checkResume` payload. Extra keys are ignored. */
37
24
  export declare function validateCheckResume(value: unknown): string[];
38
25
  /**
39
- * Resolve a typed block. Missing/invalid → localStamp off, status unset.
40
- * `ciTrustsLocalStamp` is always forced false regardless of input truthiness
41
- * (malformed non-false is validation error → fail-closed default).
26
+ * Resolve a typed block. Missing/invalid → localStamp off.
27
+ * Leftover ritual fields (status/dismissReason/ciTrustsLocalStamp) are ignored.
42
28
  */
43
29
  export declare function resolveCheckResumeFromTypedBlock(raw: unknown): CheckResumeResolved;
44
- /** Resolve `plan.policy.checkResume` from PROJECT-DEFINITION (#3189). */
30
+ /** Resolve `plan.policy.checkResume` from PROJECT-DEFINITION (#3314). */
45
31
  export declare function resolveCheckResume(projectRoot: string): CheckResumeResolved;
46
- /** Local suite stamp resume only when decided localStamp=on. */
32
+ /** Local suite stamp resume only when localStamp=on. Reserved — unused by check/release. */
47
33
  export declare function isLocalStampResumeAllowed(policy: CheckResumeResolved): boolean;
48
- /** Always false in v1 — CI must re-run suite, never trust a laptop stamp. */
49
- export declare function isCiTrustsLocalStampAllowed(_policy?: CheckResumeResolved): false;
50
34
  export declare function formatCheckResumeStatusLine(policy: CheckResumeResolved): string;
51
35
  export interface CheckResumePolicyField {
52
36
  readonly name: typeof FIELD_CHECK_RESUME;
@@ -56,17 +40,4 @@ export interface CheckResumePolicyField {
56
40
  }
57
41
  /** Inspector row for `policy:show --field=checkResume`. */
58
42
  export declare function inspectCheckResume(data: Record<string, unknown> | null, projectRoot?: string): CheckResumePolicyField;
59
- export interface WriteCheckResumeOptions {
60
- readonly localStamp: CheckResumeLocalStamp;
61
- readonly dismissReason?: string | null;
62
- readonly actor?: string;
63
- readonly note?: string;
64
- }
65
- export interface WriteCheckResumeResult {
66
- readonly exitCode: 0 | 2;
67
- readonly stdout: string;
68
- readonly changed: boolean;
69
- }
70
- /** Persist decided checkResume (preset or dismiss-with-reason). */
71
- export declare function writeCheckResume(projectRoot: string, options: WriteCheckResumeOptions): WriteCheckResumeResult;
72
43
  //# sourceMappingURL=check-resume.d.ts.map
@@ -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
- * Consent / SoT surface for consumer expansion of local suite-stamp resume
5
- * (#3188). Unset is fail-closed (localStamp off). CI never trusts a local
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 { readFileSync } from "node:fs";
9
- import { atomicWriteProjectDefinition, projectDefinitionMutationLock, } from "../vbrief-build/project-definition-io.js";
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 unset / missing. */
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
- errors.push(`${FIELD_CHECK_RESUME}.localStamp must be one of ${CHECK_RESUME_LOCAL_STAMP.join("|")}`);
57
- }
58
- if ("ciTrustsLocalStamp" in rec && rec.ciTrustsLocalStamp !== false) {
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 errors;
40
+ return [];
67
41
  }
68
42
  /**
69
- * Resolve a typed block. Missing/invalid → localStamp off, status unset.
70
- * `ciTrustsLocalStamp` is always forced false regardless of input truthiness
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 status = isStatus(block.status) ? block.status : "unset";
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 (#3189). */
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 decided localStamp=on. */
79
+ /** Local suite stamp resume only when localStamp=on. Reserved — unused by check/release. */
116
80
  export function isLocalStampResumeAllowed(policy) {
117
- return policy.status === "decided" && policy.localStamp === "on";
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
- const dismiss = policy.dismissReason !== null ? ` dismissReason=${JSON.stringify(policy.dismissReason)}` : "";
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
- * Consent / SoT surface for consumer expansion of release-originated hatch
5
- * behavior (#3187). Unset is fail-closed for behavior (mode off) but still
6
- * nags on interactive session-start until decided or dismissed with reason.
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 unset / missing / invalid. */
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, status unset.
39
- * Unset is not the same as decided-off for nag purposes.
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 (#3189). */
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 decided mode=hatch. */
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
- export interface WriteCoverageDebtOptions {
63
- readonly mode: CoverageDebtMode;
64
- readonly autoFile?: boolean;
65
- readonly dismissReason?: string | null;
66
- readonly actor?: string;
67
- readonly note?: string;
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