@deftai/directive-core 0.100.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.
Files changed (120) hide show
  1. package/dist/authz/classify.js +193 -27
  2. package/dist/authz/decompose-apply.d.ts +14 -0
  3. package/dist/authz/decompose-apply.js +93 -18
  4. package/dist/check/cached-orchestrator.d.ts +30 -5
  5. package/dist/check/cached-orchestrator.js +297 -10
  6. package/dist/check/cli-native-gates.d.ts +43 -0
  7. package/dist/check/cli-native-gates.js +84 -0
  8. package/dist/check/gate-lists.d.ts +10 -4
  9. package/dist/check/gate-lists.js +19 -5
  10. package/dist/check/index.d.ts +4 -2
  11. package/dist/check/index.js +3 -1
  12. package/dist/check/named-cause.d.ts +45 -0
  13. package/dist/check/named-cause.js +131 -0
  14. package/dist/check/orchestrator.js +6 -1
  15. package/dist/doctor/checks.d.ts +5 -6
  16. package/dist/doctor/checks.js +13 -56
  17. package/dist/doctor/help.d.ts +5 -0
  18. package/dist/doctor/help.js +31 -0
  19. package/dist/doctor/index.d.ts +2 -0
  20. package/dist/doctor/index.js +2 -0
  21. package/dist/doctor/main.js +58 -0
  22. package/dist/doctor/session-coda.d.ts +82 -0
  23. package/dist/doctor/session-coda.js +151 -0
  24. package/dist/doctor/types.d.ts +16 -0
  25. package/dist/eval/later-graduation.d.ts +39 -0
  26. package/dist/eval/later-graduation.js +91 -0
  27. package/dist/eval/report.d.ts +6 -0
  28. package/dist/eval/report.js +27 -8
  29. package/dist/index.d.ts +3 -0
  30. package/dist/index.js +3 -0
  31. package/dist/init-deposit/gitignore.js +2 -0
  32. package/dist/intake/issue-ingest.js +49 -0
  33. package/dist/policy/ac-pass-banking.d.ts +58 -0
  34. package/dist/policy/ac-pass-banking.js +150 -0
  35. package/dist/policy/ceremony-dial-escalation.d.ts +52 -0
  36. package/dist/policy/ceremony-dial-escalation.js +92 -0
  37. package/dist/policy/ceremony-dial.d.ts +32 -1
  38. package/dist/policy/ceremony-dial.js +128 -1
  39. package/dist/policy/check-resume.d.ts +9 -38
  40. package/dist/policy/check-resume.js +18 -156
  41. package/dist/policy/coverage-debt.d.ts +18 -37
  42. package/dist/policy/coverage-debt.js +38 -147
  43. package/dist/policy/index.d.ts +2 -1
  44. package/dist/policy/index.js +16 -2
  45. package/dist/preflight-cache/evaluate.d.ts +3 -0
  46. package/dist/preflight-cache/evaluate.js +3 -0
  47. package/dist/product-first-done-gate/acceptance.d.ts +25 -0
  48. package/dist/product-first-done-gate/acceptance.js +269 -0
  49. package/dist/product-first-done-gate/check-mode.d.ts +45 -0
  50. package/dist/product-first-done-gate/check-mode.js +148 -0
  51. package/dist/product-first-done-gate/empty-resolution.d.ts +26 -0
  52. package/dist/product-first-done-gate/empty-resolution.js +38 -0
  53. package/dist/product-first-done-gate/evaluate.d.ts +76 -0
  54. package/dist/product-first-done-gate/evaluate.js +411 -0
  55. package/dist/product-first-done-gate/index.d.ts +12 -0
  56. package/dist/product-first-done-gate/index.js +12 -0
  57. package/dist/product-first-done-gate/types.d.ts +67 -0
  58. package/dist/product-first-done-gate/types.js +54 -0
  59. package/dist/run-summary/emit.d.ts +66 -0
  60. package/dist/run-summary/emit.js +217 -0
  61. package/dist/run-summary/index.d.ts +5 -0
  62. package/dist/run-summary/index.js +5 -0
  63. package/dist/run-summary/path.d.ts +25 -0
  64. package/dist/run-summary/path.js +78 -0
  65. package/dist/run-summary/share.d.ts +25 -0
  66. package/dist/run-summary/share.js +106 -0
  67. package/dist/run-summary/types.d.ts +134 -0
  68. package/dist/run-summary/types.js +28 -0
  69. package/dist/scope/acceptance-activate-gate.d.ts +23 -0
  70. package/dist/scope/acceptance-activate-gate.js +70 -0
  71. package/dist/scope/acceptance-evidence.d.ts +34 -0
  72. package/dist/scope/acceptance-evidence.js +84 -10
  73. package/dist/scope/decompose.d.ts +5 -0
  74. package/dist/scope/decompose.js +11 -2
  75. package/dist/scope/index.d.ts +1 -0
  76. package/dist/scope/index.js +1 -0
  77. package/dist/scope/transition.js +5 -0
  78. package/dist/session/ac-pass-banking.d.ts +221 -0
  79. package/dist/session/ac-pass-banking.js +761 -0
  80. package/dist/session/deposit-sha.d.ts +49 -0
  81. package/dist/session/deposit-sha.js +121 -0
  82. package/dist/session/effort-budget.d.ts +6 -0
  83. package/dist/session/effort-budget.js +21 -3
  84. package/dist/session/index.d.ts +5 -1
  85. package/dist/session/index.js +5 -1
  86. package/dist/session/orientation-compression.d.ts +127 -0
  87. package/dist/session/orientation-compression.js +435 -0
  88. package/dist/session/orientation-state.d.ts +29 -0
  89. package/dist/session/orientation-state.js +85 -0
  90. package/dist/session/session-start.d.ts +31 -0
  91. package/dist/session/session-start.js +219 -22
  92. package/dist/session/toolchain-preflight.d.ts +79 -0
  93. package/dist/session/toolchain-preflight.js +211 -0
  94. package/dist/triage/bootstrap/gitignore.d.ts +1 -1
  95. package/dist/triage/bootstrap/gitignore.js +8 -2
  96. package/dist/triage/bootstrap/index.js +15 -3
  97. package/dist/triage/classify/index.d.ts +1 -0
  98. package/dist/triage/classify/index.js +2 -0
  99. package/dist/triage/classify/label-mirror.js +16 -0
  100. package/dist/triage/classify/mirror-discovery-tip.d.ts +95 -0
  101. package/dist/triage/classify/mirror-discovery-tip.js +234 -0
  102. package/dist/triage/reconcile/reconcile.js +28 -6
  103. package/dist/triage/summary/index.js +12 -4
  104. package/dist/triage/welcome/default-mode.js +16 -0
  105. package/dist/ts-check-lane/run-lane.js +21 -4
  106. package/dist/vbrief-validate/conformance.js +7 -0
  107. package/dist/verify-ac/clauses.d.ts +51 -0
  108. package/dist/verify-ac/clauses.js +490 -0
  109. package/dist/verify-ac/evaluate.d.ts +55 -0
  110. package/dist/verify-ac/evaluate.js +145 -0
  111. package/dist/verify-ac/flag.d.ts +35 -0
  112. package/dist/verify-ac/flag.js +104 -0
  113. package/dist/verify-ac/index.d.ts +10 -0
  114. package/dist/verify-ac/index.js +10 -0
  115. package/dist/vitest-runner/coverage-debt-teardown.js +16 -4
  116. package/package.json +15 -3
  117. package/dist/policy/coverage-check-resume-presets.d.ts +0 -46
  118. package/dist/policy/coverage-check-resume-presets.js +0 -228
  119. package/dist/session/coverage-check-resume-nudge.d.ts +0 -34
  120. package/dist/session/coverage-check-resume-nudge.js +0 -66
@@ -1,5 +1,6 @@
1
1
  import { FIELD_HOST_SKILL_DISCOVERY, FIELD_HOST_SKILL_DISCOVERY_CLI_ALIAS, inspectHostSkillDiscovery, } from "../init-deposit/skill-discovery-hosts.js";
2
2
  import { FIELD_OPENCLAW_PRODUCT_COMMANDS, FIELD_OPENCLAW_PRODUCT_COMMANDS_CLI_ALIAS, inspectOpenClawProductCommands, } from "../slash/openclaw-deposit.js";
3
+ import { FIELD_AC_PASS_BANKING, FIELD_AC_PASS_BANKING_CLI_ALIAS, inspectAcPassBanking, } from "./ac-pass-banking.js";
3
4
  import { FIELD_CEREMONY_DIAL, FIELD_CEREMONY_DIAL_CLI_ALIAS, inspectCeremonyDial, } from "./ceremony-dial.js";
4
5
  import { FIELD_CHECK_RESUME, FIELD_CHECK_RESUME_CLI_ALIAS, inspectCheckResume, } from "./check-resume.js";
5
6
  import { FIELD_COVERAGE_DEBT, FIELD_COVERAGE_DEBT_CLI_ALIAS, inspectCoverageDebt, } from "./coverage-debt.js";
@@ -16,12 +17,13 @@ import { FIELD_RUNTIME_AUTHORITY, FIELD_RUNTIME_AUTHORITY_CLI_ALIAS, inspectRunt
16
17
  import { FIELD_STALENESS_TICKLER, FIELD_STALENESS_TICKLER_CLI_ALIAS, inspectStalenessTickler, } from "./staleness-tickler.js";
17
18
  import { FIELD_VALUE_FEEDBACK, FIELD_VALUE_FEEDBACK_CLI_ALIAS, inspectValueFeedback, } from "./value-feedback.js";
18
19
  import { DEFAULT_WIP_CAP } from "./wip.js";
20
+ export * from "./ac-pass-banking.js";
19
21
  export * from "./agents-md-advisory.js";
20
22
  export * from "./autonomy.js";
21
23
  export * from "./capacity.js";
22
24
  export * from "./ceremony-dial.js";
25
+ export * from "./ceremony-dial-escalation.js";
23
26
  export * from "./check-resume.js";
24
- export * from "./coverage-check-resume-presets.js";
25
27
  export * from "./coverage-debt.js";
26
28
  export * from "./decisions.js";
27
29
  export * from "./deft-directive-disable.js";
@@ -420,6 +422,15 @@ function inspectCeremonyDialField(data, projectRoot) {
420
422
  source: field.source,
421
423
  };
422
424
  }
425
+ function inspectAcPassBankingField(data, projectRoot) {
426
+ const field = inspectAcPassBanking(data, projectRoot);
427
+ return {
428
+ name: field.name,
429
+ current: field.current,
430
+ default: field.default,
431
+ source: field.source,
432
+ };
433
+ }
423
434
  const REGISTERED_POLICIES = [
424
435
  inspectAllowDirectCommits,
425
436
  inspectWipCap,
@@ -448,6 +459,7 @@ const REGISTERED_POLICIES = [
448
459
  inspectRequireHumanMergeField,
449
460
  inspectHotfixCriteriaField,
450
461
  inspectCeremonyDialField,
462
+ inspectAcPassBankingField,
451
463
  ];
452
464
  /** Walk registered inspectors and return one row per field (#1148). */
453
465
  export function inspectAllPolicies(projectRoot) {
@@ -486,7 +498,9 @@ export function inspectOnePolicy(name, projectRoot) {
486
498
  ? FIELD_MIN_GREPTILE_CONFIDENCE
487
499
  : name === FIELD_CEREMONY_DIAL_CLI_ALIAS
488
500
  ? FIELD_CEREMONY_DIAL
489
- : name;
501
+ : name === FIELD_AC_PASS_BANKING_CLI_ALIAS
502
+ ? FIELD_AC_PASS_BANKING
503
+ : name;
490
504
  for (const field of inspectAllPolicies(projectRoot)) {
491
505
  if (field.name === normalized)
492
506
  return field;
@@ -44,6 +44,9 @@ export declare function normaliseRepoUrl(url: string): string | null;
44
44
  * Evaluate cache freshness for the given project root.
45
45
  *
46
46
  * Faithful port of scripts/preflight_cache.py::evaluate().
47
+ * #3286 note: deposit-sha orientation no-ops live in session orientation
48
+ * composition (age-gated), not here — triage cache freshness is age/drift based
49
+ * and must not short-circuit solely on payload/templates/engine fingerprints.
47
50
  */
48
51
  export declare function evaluate(projectRoot: string, options?: EvaluateOptions): GateResult;
49
52
  //# sourceMappingURL=evaluate.d.ts.map
@@ -317,6 +317,9 @@ const REMEDIATION_NO_CANDIDATES = [
317
317
  * Evaluate cache freshness for the given project root.
318
318
  *
319
319
  * Faithful port of scripts/preflight_cache.py::evaluate().
320
+ * #3286 note: deposit-sha orientation no-ops live in session orientation
321
+ * composition (age-gated), not here — triage cache freshness is age/drift based
322
+ * and must not short-circuit solely on payload/templates/engine fingerprints.
320
323
  */
321
324
  export function evaluate(projectRoot, options = {}) {
322
325
  return evaluateWithContext(projectRoot, options, { afterEmptyPopulate: false });
@@ -0,0 +1,25 @@
1
+ /**
2
+ * plan.acceptance schema helpers (#3284).
3
+ *
4
+ * Captures stated acceptance.commands at intake; empty requires none_stated:true.
5
+ * Interoperates with #3267 plan.metadata.literal_acceptance_commands.
6
+ */
7
+ import { type AcceptanceCommand, type PlanAcceptance } from "./types.js";
8
+ /** Validation errors for a plan.acceptance object (empty list = valid). */
9
+ export declare function validatePlanAcceptance(value: unknown): string[];
10
+ /**
11
+ * Read plan.acceptance when present; otherwise synthesize from #3267
12
+ * literal_acceptance_commands / empty+none_stated.
13
+ */
14
+ export declare function readPlanAcceptance(plan: Record<string, unknown> | null | undefined): PlanAcceptance;
15
+ /** Attach a validated PlanAcceptance onto plan.acceptance + mirror to #3267 metadata. */
16
+ export declare function attachPlanAcceptance(plan: Record<string, unknown>, acceptance: PlanAcceptance): Record<string, unknown>;
17
+ /**
18
+ * Build plan.acceptance from intake capture (#3284).
19
+ * Stated commands → none_stated:false, source_rung:stated.
20
+ * No stated commands → none_stated:true, source_rung:project_floor (until agent derives).
21
+ */
22
+ export declare function buildAcceptanceFromIntakeCapture(capturedCommands: readonly AcceptanceCommand[]): PlanAcceptance;
23
+ /** Stamp plan.acceptance from existing literal capture after issue ingest. */
24
+ export declare function stampAcceptanceFromLiteralCapture(plan: Record<string, unknown>): Record<string, unknown>;
25
+ //# sourceMappingURL=acceptance.d.ts.map
@@ -0,0 +1,269 @@
1
+ /**
2
+ * plan.acceptance schema helpers (#3284).
3
+ *
4
+ * Captures stated acceptance.commands at intake; empty requires none_stated:true.
5
+ * Interoperates with #3267 plan.metadata.literal_acceptance_commands.
6
+ */
7
+ import { attachLiteralAcceptanceCommands, readStoredLiteralAcceptanceCommands, } from "../literal-acceptance/index.js";
8
+ import { readAcceptanceClauses, serializeAcceptanceClauses } from "../verify-ac/clauses.js";
9
+ import { PLAN_ACCEPTANCE_KEY, } from "./types.js";
10
+ function asRecord(value) {
11
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
12
+ return value;
13
+ }
14
+ return null;
15
+ }
16
+ function isNonEmptyString(value) {
17
+ return typeof value === "string" && value.trim().length > 0;
18
+ }
19
+ function coerceCommands(raw) {
20
+ if (!Array.isArray(raw))
21
+ return [];
22
+ const out = [];
23
+ for (const entry of raw) {
24
+ if (typeof entry === "string") {
25
+ const command = entry.trim();
26
+ if (command.length > 0)
27
+ out.push({ command });
28
+ continue;
29
+ }
30
+ const rec = asRecord(entry);
31
+ if (rec === null)
32
+ continue;
33
+ const command = rec.command ?? rec.cmd ?? rec.shell;
34
+ if (!isNonEmptyString(command))
35
+ continue;
36
+ out.push({
37
+ command: command.trim(),
38
+ cwd: isNonEmptyString(rec.cwd) ? rec.cwd.trim() : null,
39
+ expectedStdout: isNonEmptyString(rec.expectedStdout)
40
+ ? rec.expectedStdout
41
+ : isNonEmptyString(rec.expected_stdout)
42
+ ? rec.expected_stdout
43
+ : null,
44
+ expectedExitCode: typeof rec.expectedExitCode === "number"
45
+ ? rec.expectedExitCode
46
+ : typeof rec.expected_exit_code === "number"
47
+ ? rec.expected_exit_code
48
+ : 0,
49
+ });
50
+ }
51
+ return out;
52
+ }
53
+ function isAcSourceRung(value) {
54
+ return value === "stated" || value === "derived" || value === "project_floor";
55
+ }
56
+ /** Validation errors for a plan.acceptance object (empty list = valid). */
57
+ export function validatePlanAcceptance(value) {
58
+ if (value === null || value === undefined) {
59
+ return [];
60
+ }
61
+ const rec = asRecord(value);
62
+ if (rec === null) {
63
+ return ["plan.acceptance must be an object"];
64
+ }
65
+ const errors = [];
66
+ if ("commands" in rec && rec.commands !== undefined && !Array.isArray(rec.commands)) {
67
+ errors.push("plan.acceptance.commands must be an array");
68
+ }
69
+ if ("none_stated" in rec &&
70
+ rec.none_stated !== undefined &&
71
+ typeof rec.none_stated !== "boolean") {
72
+ errors.push("plan.acceptance.none_stated must be a boolean");
73
+ }
74
+ if ("source_rung" in rec && rec.source_rung !== undefined && !isAcSourceRung(rec.source_rung)) {
75
+ errors.push('plan.acceptance.source_rung must be "stated" | "derived" | "project_floor"');
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
+ }
93
+ const commands = coerceCommands(rec.commands);
94
+ const noneStated = rec.none_stated === true;
95
+ if (commands.length === 0 && !noneStated) {
96
+ errors.push("plan.acceptance.commands is empty but none_stated is not true — " +
97
+ "empty acceptance is only allowed with an explicit none_stated: true marker (#3284)");
98
+ }
99
+ if (commands.length > 0 && noneStated && rec.source_rung === "stated") {
100
+ errors.push("plan.acceptance: none_stated:true with source_rung:stated is contradictory " +
101
+ "(use source_rung:derived when commands are agent-authored under none_stated)");
102
+ }
103
+ return errors;
104
+ }
105
+ /**
106
+ * Read plan.acceptance when present; otherwise synthesize from #3267
107
+ * literal_acceptance_commands / empty+none_stated.
108
+ */
109
+ export function readPlanAcceptance(plan) {
110
+ if (plan === null || plan === undefined) {
111
+ return { commands: [], none_stated: true, source_rung: "project_floor" };
112
+ }
113
+ const raw = plan[PLAN_ACCEPTANCE_KEY];
114
+ if (raw !== null && raw !== undefined) {
115
+ const rec = asRecord(raw);
116
+ if (rec !== null) {
117
+ const commands = coerceCommands(rec.commands);
118
+ const noneStated = rec.none_stated === true || (commands.length === 0 && rec.none_stated !== false);
119
+ let sourceRung = isAcSourceRung(rec.source_rung)
120
+ ? rec.source_rung
121
+ : commands.length > 0
122
+ ? "stated"
123
+ : "project_floor";
124
+ if (noneStated && commands.length > 0 && sourceRung === "stated") {
125
+ sourceRung = "derived";
126
+ }
127
+ if (noneStated && commands.length === 0) {
128
+ sourceRung = isAcSourceRung(rec.source_rung) ? rec.source_rung : "project_floor";
129
+ }
130
+ const clauses = readAcceptanceClauses(rec);
131
+ return {
132
+ commands,
133
+ none_stated: noneStated,
134
+ source_rung: sourceRung,
135
+ derived_reason: isNonEmptyString(rec.derived_reason)
136
+ ? rec.derived_reason
137
+ : isNonEmptyString(rec.derivedReason)
138
+ ? rec.derivedReason
139
+ : null,
140
+ ...(clauses.length > 0 ? { clauses } : {}),
141
+ };
142
+ }
143
+ }
144
+ // Fallback: #3267 metadata ledger.
145
+ const literal = readStoredLiteralAcceptanceCommands(plan);
146
+ if (literal.length > 0) {
147
+ return {
148
+ commands: literal.map(literalToAcceptance),
149
+ none_stated: false,
150
+ source_rung: "stated",
151
+ derived_reason: null,
152
+ };
153
+ }
154
+ return {
155
+ commands: [],
156
+ none_stated: true,
157
+ source_rung: "project_floor",
158
+ derived_reason: "no plan.acceptance and no literal_acceptance_commands (#3284 floor)",
159
+ };
160
+ }
161
+ function literalToAcceptance(cmd) {
162
+ return {
163
+ command: cmd.command,
164
+ cwd: cmd.cwd ?? null,
165
+ expectedStdout: cmd.expectedStdout ?? null,
166
+ expectedExitCode: cmd.expectedExitCode ?? 0,
167
+ };
168
+ }
169
+ function acceptanceToLiteral(cmd, source) {
170
+ return {
171
+ command: cmd.command,
172
+ cwd: cmd.cwd ?? null,
173
+ expectedStdout: cmd.expectedStdout ?? null,
174
+ expectedExitCode: cmd.expectedExitCode ?? 0,
175
+ source,
176
+ sourceSpan: "plan.acceptance.commands",
177
+ };
178
+ }
179
+ /** Attach a validated PlanAcceptance onto plan.acceptance + mirror to #3267 metadata. */
180
+ export function attachPlanAcceptance(plan, acceptance) {
181
+ const errors = validatePlanAcceptance(acceptance);
182
+ if (errors.length > 0) {
183
+ throw new Error(`attachPlanAcceptance: ${errors.join("; ")}`);
184
+ }
185
+ const serializable = {
186
+ commands: acceptance.commands.map((c) => {
187
+ const row = { command: c.command };
188
+ if (c.cwd)
189
+ row.cwd = c.cwd;
190
+ if (c.expectedStdout)
191
+ row.expectedStdout = c.expectedStdout;
192
+ if (typeof c.expectedExitCode === "number" && c.expectedExitCode !== 0) {
193
+ row.expectedExitCode = c.expectedExitCode;
194
+ }
195
+ return row;
196
+ }),
197
+ none_stated: acceptance.none_stated,
198
+ source_rung: acceptance.source_rung,
199
+ };
200
+ if (acceptance.derived_reason) {
201
+ serializable.derived_reason = acceptance.derived_reason;
202
+ }
203
+ if (acceptance.clauses !== undefined && acceptance.clauses.length > 0) {
204
+ serializable.clauses = serializeAcceptanceClauses(acceptance.clauses);
205
+ }
206
+ let next = {
207
+ ...plan,
208
+ [PLAN_ACCEPTANCE_KEY]: serializable,
209
+ };
210
+ // Mirror executable commands into #3267 ledger for verify:literal-ac interoperability.
211
+ if (acceptance.commands.length > 0) {
212
+ const source = acceptance.source_rung === "stated" ? "task_statement" : "explicit";
213
+ // derived / floor commands are agent-authored → executable source=explicit
214
+ const literalSource = acceptance.source_rung === "stated" ? "task_statement" : "explicit";
215
+ void source;
216
+ next = attachLiteralAcceptanceCommands(next, acceptance.commands.map((c) => acceptanceToLiteral(c, literalSource)));
217
+ }
218
+ return next;
219
+ }
220
+ /**
221
+ * Build plan.acceptance from intake capture (#3284).
222
+ * Stated commands → none_stated:false, source_rung:stated.
223
+ * No stated commands → none_stated:true, source_rung:project_floor (until agent derives).
224
+ */
225
+ export function buildAcceptanceFromIntakeCapture(capturedCommands) {
226
+ if (capturedCommands.length === 0) {
227
+ return {
228
+ commands: [],
229
+ none_stated: true,
230
+ source_rung: "project_floor",
231
+ derived_reason: "no shell acceptance commands stated in task text; floor until agent derives AC (#3284 ladder)",
232
+ };
233
+ }
234
+ return {
235
+ commands: capturedCommands,
236
+ none_stated: false,
237
+ source_rung: "stated",
238
+ derived_reason: null,
239
+ };
240
+ }
241
+ /** Stamp plan.acceptance from existing literal capture after issue ingest. */
242
+ export function stampAcceptanceFromLiteralCapture(plan) {
243
+ const literal = readStoredLiteralAcceptanceCommands(plan);
244
+ const acceptance = buildAcceptanceFromIntakeCapture(literal.map(literalToAcceptance));
245
+ // Avoid re-mirroring task_statement into verify_commands (ingest strips those).
246
+ const serializable = {
247
+ commands: acceptance.commands.map((c) => {
248
+ const row = { command: c.command };
249
+ if (c.cwd)
250
+ row.cwd = c.cwd;
251
+ if (c.expectedStdout)
252
+ row.expectedStdout = c.expectedStdout;
253
+ if (typeof c.expectedExitCode === "number" && c.expectedExitCode !== 0) {
254
+ row.expectedExitCode = c.expectedExitCode;
255
+ }
256
+ return row;
257
+ }),
258
+ none_stated: acceptance.none_stated,
259
+ source_rung: acceptance.source_rung,
260
+ };
261
+ if (acceptance.derived_reason) {
262
+ serializable.derived_reason = acceptance.derived_reason;
263
+ }
264
+ return {
265
+ ...plan,
266
+ [PLAN_ACCEPTANCE_KEY]: serializable,
267
+ };
268
+ }
269
+ //# sourceMappingURL=acceptance.js.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Resolve product-first check composition mode (#3284).
3
+ *
4
+ * Priority (highest wins):
5
+ * 1. DEFT_CHECK_AC_ONLY / DEFT_CHECK_MODE=rapid → rapid (AC-only)
6
+ * 2. DEFT_CHECK_MODE=pressure|degraded or DEFT_HYGIENE_ADVISORY → pressure
7
+ * 3. ceremony dial depth rapid|minimal → rapid
8
+ * 4. hard effort budget (#3266) → pressure
9
+ * 5. default full
10
+ */
11
+ import { type CeremonyDepth } from "../policy/ceremony-dial.js";
12
+ import { type ProductFirstCheckMode } from "./types.js";
13
+ export interface ResolveProductFirstCheckModeInput {
14
+ readonly environ?: Readonly<Record<string, string | undefined>>;
15
+ readonly projectRoot?: string;
16
+ /** Inject ceremony depth (tests); when unset, reads ritual-state audit. */
17
+ readonly ceremonyDepth?: CeremonyDepth | null;
18
+ /** Inject hard-budget detected flag (tests). */
19
+ readonly hardBudgetDetected?: boolean;
20
+ }
21
+ export interface ProductFirstCheckModeResolution {
22
+ readonly mode: ProductFirstCheckMode;
23
+ readonly sources: readonly string[];
24
+ readonly hygieneAdvisory: boolean;
25
+ readonly acOnly: boolean;
26
+ /** AC remains mandatory whenever mode is not a pure no-op. */
27
+ readonly acMandatory: true;
28
+ }
29
+ /**
30
+ * Resolve the active product-first check mode from env + ceremony + budget.
31
+ */
32
+ export declare function resolveProductFirstCheckMode(input?: ResolveProductFirstCheckModeInput): ProductFirstCheckModeResolution;
33
+ /** True when this gate id is the product AC gate. */
34
+ export declare function isProductAcGate(gateId: string): boolean;
35
+ /** True when this gate is classified as hygiene (may be advisory under pressure). */
36
+ export declare function isHygieneGate(gateId: string): boolean;
37
+ /**
38
+ * Filter / annotate gate list for the resolved mode.
39
+ * - rapid: only product AC gates
40
+ * - pressure/full: full list (pressure marks hygiene advisory at run time)
41
+ */
42
+ export declare function applyProductFirstGateMode<T extends string | {
43
+ readonly task: string;
44
+ }>(gates: readonly T[], mode: ProductFirstCheckMode, gateIdOf?: (g: T) => string): readonly T[];
45
+ //# sourceMappingURL=check-mode.d.ts.map
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Resolve product-first check composition mode (#3284).
3
+ *
4
+ * Priority (highest wins):
5
+ * 1. DEFT_CHECK_AC_ONLY / DEFT_CHECK_MODE=rapid → rapid (AC-only)
6
+ * 2. DEFT_CHECK_MODE=pressure|degraded or DEFT_HYGIENE_ADVISORY → pressure
7
+ * 3. ceremony dial depth rapid|minimal → rapid
8
+ * 4. hard effort budget (#3266) → pressure
9
+ * 5. default full
10
+ */
11
+ import { CEREMONY_DEPTHS, readCeremonyDialAudit, } from "../policy/ceremony-dial.js";
12
+ import { detectHardEffortBudget } from "../session/effort-budget.js";
13
+ import { ENV_CHECK_AC_ONLY, ENV_CHECK_MODE, ENV_HYGIENE_ADVISORY, HYGIENE_GATE_ID_PREFIXES, PRODUCT_AC_GATE_ID, } from "./types.js";
14
+ function asCeremonyDepth(value) {
15
+ return typeof value === "string" && CEREMONY_DEPTHS.includes(value)
16
+ ? value
17
+ : null;
18
+ }
19
+ const TRUTHY = new Set(["1", "true", "yes", "on"]);
20
+ function isTruthy(raw) {
21
+ if (raw === undefined)
22
+ return false;
23
+ return TRUTHY.has(raw.trim().toLowerCase());
24
+ }
25
+ function normalizeModeToken(raw) {
26
+ const t = raw.trim().toLowerCase();
27
+ if (t === "full" || t === "standard")
28
+ return "full";
29
+ if (t === "pressure" || t === "degraded" || t === "advisory")
30
+ return "pressure";
31
+ if (t === "rapid" || t === "minimal" || t === "ac-only" || t === "ac_only")
32
+ return "rapid";
33
+ return null;
34
+ }
35
+ /**
36
+ * Resolve the active product-first check mode from env + ceremony + budget.
37
+ */
38
+ export function resolveProductFirstCheckMode(input = {}) {
39
+ const env = input.environ ?? process.env;
40
+ const sources = [];
41
+ if (isTruthy(env[ENV_CHECK_AC_ONLY])) {
42
+ sources.push(`${ENV_CHECK_AC_ONLY}=truthy`);
43
+ return {
44
+ mode: "rapid",
45
+ sources,
46
+ hygieneAdvisory: true,
47
+ acOnly: true,
48
+ acMandatory: true,
49
+ };
50
+ }
51
+ const modeEnv = env[ENV_CHECK_MODE];
52
+ if (typeof modeEnv === "string" && modeEnv.trim().length > 0) {
53
+ const parsed = normalizeModeToken(modeEnv);
54
+ if (parsed !== null) {
55
+ sources.push(`${ENV_CHECK_MODE}=${modeEnv.trim()}`);
56
+ return {
57
+ mode: parsed,
58
+ sources,
59
+ hygieneAdvisory: parsed !== "full",
60
+ acOnly: parsed === "rapid",
61
+ acMandatory: true,
62
+ };
63
+ }
64
+ }
65
+ if (isTruthy(env[ENV_HYGIENE_ADVISORY])) {
66
+ sources.push(`${ENV_HYGIENE_ADVISORY}=truthy`);
67
+ return {
68
+ mode: "pressure",
69
+ sources,
70
+ hygieneAdvisory: true,
71
+ acOnly: false,
72
+ acMandatory: true,
73
+ };
74
+ }
75
+ let depth = input.ceremonyDepth;
76
+ if (depth === undefined && input.projectRoot !== undefined) {
77
+ try {
78
+ const audit = readCeremonyDialAudit(input.projectRoot);
79
+ depth = asCeremonyDepth(audit.depth);
80
+ if (depth !== null)
81
+ sources.push(`ceremony_dial.depth=${depth}`);
82
+ }
83
+ catch {
84
+ depth = null;
85
+ }
86
+ }
87
+ if (depth === "rapid" || depth === "minimal") {
88
+ if (!sources.some((s) => s.startsWith("ceremony_dial"))) {
89
+ sources.push(`ceremonyDepth=${depth}`);
90
+ }
91
+ return {
92
+ mode: "rapid",
93
+ sources,
94
+ hygieneAdvisory: true,
95
+ acOnly: true,
96
+ acMandatory: true,
97
+ };
98
+ }
99
+ let hardBudget = input.hardBudgetDetected;
100
+ if (hardBudget === undefined) {
101
+ hardBudget = detectHardEffortBudget({ environ: env }).detected;
102
+ if (hardBudget)
103
+ sources.push("hard_effort_budget");
104
+ }
105
+ else if (hardBudget) {
106
+ sources.push("hard_effort_budget(injected)");
107
+ }
108
+ if (hardBudget === true) {
109
+ return {
110
+ mode: "pressure",
111
+ sources,
112
+ hygieneAdvisory: true,
113
+ acOnly: false,
114
+ acMandatory: true,
115
+ };
116
+ }
117
+ sources.push("default:full");
118
+ return {
119
+ mode: "full",
120
+ sources,
121
+ hygieneAdvisory: false,
122
+ acOnly: false,
123
+ acMandatory: true,
124
+ };
125
+ }
126
+ /** True when this gate id is the product AC gate. */
127
+ export function isProductAcGate(gateId) {
128
+ return gateId === PRODUCT_AC_GATE_ID || gateId === "verify:literal-ac";
129
+ }
130
+ /** True when this gate is classified as hygiene (may be advisory under pressure). */
131
+ export function isHygieneGate(gateId) {
132
+ if (isProductAcGate(gateId))
133
+ return false;
134
+ return HYGIENE_GATE_ID_PREFIXES.includes(gateId);
135
+ }
136
+ /**
137
+ * Filter / annotate gate list for the resolved mode.
138
+ * - rapid: only product AC gates
139
+ * - pressure/full: full list (pressure marks hygiene advisory at run time)
140
+ */
141
+ export function applyProductFirstGateMode(gates, mode, gateIdOf = (g) => (typeof g === "string" ? g : g.task)) {
142
+ if (mode === "rapid") {
143
+ const ac = gates.filter((g) => isProductAcGate(gateIdOf(g)));
144
+ return ac.length > 0 ? ac : gates.filter((g) => gateIdOf(g) === PRODUCT_AC_GATE_ID);
145
+ }
146
+ return gates;
147
+ }
148
+ //# sourceMappingURL=check-mode.js.map
@@ -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