@deftai/directive-core 0.99.0 → 0.101.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 (166) hide show
  1. package/dist/authz/actions.d.ts +6 -0
  2. package/dist/authz/actions.js +3 -0
  3. package/dist/authz/classify.js +241 -30
  4. package/dist/authz/decompose-apply.d.ts +81 -0
  5. package/dist/authz/decompose-apply.js +377 -0
  6. package/dist/authz/index.d.ts +3 -1
  7. package/dist/authz/index.js +3 -1
  8. package/dist/authz/store.d.ts +53 -0
  9. package/dist/authz/store.js +219 -1
  10. package/dist/authz/types.d.ts +19 -2
  11. package/dist/authz/types.js +5 -1
  12. package/dist/check/cached-orchestrator.d.ts +26 -5
  13. package/dist/check/cached-orchestrator.js +228 -6
  14. package/dist/check/gate-lists.d.ts +10 -4
  15. package/dist/check/gate-lists.js +19 -5
  16. package/dist/check/index.d.ts +3 -2
  17. package/dist/check/index.js +2 -1
  18. package/dist/check/named-cause.d.ts +45 -0
  19. package/dist/check/named-cause.js +121 -0
  20. package/dist/check/orchestrator.js +6 -1
  21. package/dist/doctor/checks.d.ts +44 -0
  22. package/dist/doctor/checks.js +428 -2
  23. package/dist/doctor/help.d.ts +5 -0
  24. package/dist/doctor/help.js +31 -0
  25. package/dist/doctor/index.d.ts +2 -0
  26. package/dist/doctor/index.js +2 -0
  27. package/dist/doctor/main.d.ts +6 -7
  28. package/dist/doctor/main.js +130 -79
  29. package/dist/doctor/session-coda.d.ts +82 -0
  30. package/dist/doctor/session-coda.js +151 -0
  31. package/dist/doctor/types.d.ts +16 -0
  32. package/dist/doctor/which.d.ts +20 -1
  33. package/dist/doctor/which.js +67 -1
  34. package/dist/finish-loop/pr-finish-loop.d.ts +13 -2
  35. package/dist/finish-loop/pr-finish-loop.js +116 -5
  36. package/dist/finish-loop/types.d.ts +1 -1
  37. package/dist/hooks/dispatcher.d.ts +9 -5
  38. package/dist/hooks/dispatcher.js +23 -15
  39. package/dist/hooks/readonly.d.ts +6 -3
  40. package/dist/hooks/readonly.js +44 -25
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.js +3 -0
  43. package/dist/init-deposit/agent-hooks.d.ts +20 -0
  44. package/dist/init-deposit/agent-hooks.js +51 -31
  45. package/dist/init-deposit/gitignore.js +2 -0
  46. package/dist/intake/issue-ingest.js +36 -0
  47. package/dist/lifecycle/completed-consistency.d.ts +60 -0
  48. package/dist/lifecycle/completed-consistency.js +443 -0
  49. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +47 -0
  50. package/dist/lifecycle/completed-tracked-on-delivery.js +415 -0
  51. package/dist/lifecycle/index.d.ts +2 -0
  52. package/dist/lifecycle/index.js +2 -0
  53. package/dist/literal-acceptance/capture.d.ts +52 -0
  54. package/dist/literal-acceptance/capture.js +658 -0
  55. package/dist/literal-acceptance/evaluate.d.ts +47 -0
  56. package/dist/literal-acceptance/evaluate.js +193 -0
  57. package/dist/literal-acceptance/index.d.ts +12 -0
  58. package/dist/literal-acceptance/index.js +12 -0
  59. package/dist/literal-acceptance/run.d.ts +38 -0
  60. package/dist/literal-acceptance/run.js +216 -0
  61. package/dist/literal-acceptance/safety.d.ts +24 -0
  62. package/dist/literal-acceptance/safety.js +251 -0
  63. package/dist/literal-acceptance/types.d.ts +82 -0
  64. package/dist/literal-acceptance/types.js +26 -0
  65. package/dist/policy/ac-pass-banking.d.ts +58 -0
  66. package/dist/policy/ac-pass-banking.js +150 -0
  67. package/dist/policy/ceremony-dial.d.ts +96 -11
  68. package/dist/policy/ceremony-dial.js +250 -23
  69. package/dist/policy/index.d.ts +2 -0
  70. package/dist/policy/index.js +16 -1
  71. package/dist/policy/merge-approval-head.d.ts +129 -0
  72. package/dist/policy/merge-approval-head.js +461 -0
  73. package/dist/policy/require-human-merge.d.ts +5 -0
  74. package/dist/policy/require-human-merge.js +5 -0
  75. package/dist/pr-merge-readiness/ci-gate.d.ts +20 -3
  76. package/dist/pr-merge-readiness/ci-gate.js +65 -5
  77. package/dist/pr-merge-readiness/compute.d.ts +13 -0
  78. package/dist/pr-merge-readiness/compute.js +99 -14
  79. package/dist/pr-merge-readiness/gh.d.ts +49 -0
  80. package/dist/pr-merge-readiness/gh.js +268 -0
  81. package/dist/pr-merge-readiness/index.d.ts +2 -2
  82. package/dist/pr-merge-readiness/index.js +2 -2
  83. package/dist/pr-merge-readiness/test-gh-fixtures.helpers.js +4 -0
  84. package/dist/pr-wait-mergeable/cascade.d.ts +11 -0
  85. package/dist/pr-wait-mergeable/cascade.js +115 -1
  86. package/dist/pr-wait-mergeable/main.d.ts +4 -0
  87. package/dist/pr-wait-mergeable/main.js +4 -0
  88. package/dist/pr-wait-mergeable/types.d.ts +3 -1
  89. package/dist/pr-wait-mergeable/wrappers.d.ts +6 -1
  90. package/dist/pr-wait-mergeable/wrappers.js +7 -1
  91. package/dist/preflight/evaluate.d.ts +15 -1
  92. package/dist/preflight/evaluate.js +33 -2
  93. package/dist/preflight-cache/evaluate.d.ts +3 -0
  94. package/dist/preflight-cache/evaluate.js +3 -0
  95. package/dist/product-first-done-gate/acceptance.d.ts +25 -0
  96. package/dist/product-first-done-gate/acceptance.js +247 -0
  97. package/dist/product-first-done-gate/check-mode.d.ts +45 -0
  98. package/dist/product-first-done-gate/check-mode.js +148 -0
  99. package/dist/product-first-done-gate/evaluate.d.ts +50 -0
  100. package/dist/product-first-done-gate/evaluate.js +255 -0
  101. package/dist/product-first-done-gate/index.d.ts +11 -0
  102. package/dist/product-first-done-gate/index.js +11 -0
  103. package/dist/product-first-done-gate/types.d.ts +64 -0
  104. package/dist/product-first-done-gate/types.js +61 -0
  105. package/dist/render/framework-commands.js +4 -0
  106. package/dist/run-summary/emit.d.ts +56 -0
  107. package/dist/run-summary/emit.js +171 -0
  108. package/dist/run-summary/index.d.ts +4 -0
  109. package/dist/run-summary/index.js +4 -0
  110. package/dist/run-summary/path.d.ts +25 -0
  111. package/dist/run-summary/path.js +78 -0
  112. package/dist/run-summary/types.d.ts +76 -0
  113. package/dist/run-summary/types.js +21 -0
  114. package/dist/scope/acceptance-evidence.d.ts +110 -0
  115. package/dist/scope/acceptance-evidence.js +422 -0
  116. package/dist/scope/coverage-map.d.ts +98 -0
  117. package/dist/scope/coverage-map.js +558 -0
  118. package/dist/scope/decompose.d.ts +5 -0
  119. package/dist/scope/decompose.js +134 -11
  120. package/dist/scope/index.d.ts +3 -0
  121. package/dist/scope/index.js +3 -0
  122. package/dist/scope/parent-lineage.d.ts +125 -0
  123. package/dist/scope/parent-lineage.js +626 -0
  124. package/dist/scope/transition.d.ts +8 -0
  125. package/dist/scope/transition.js +61 -2
  126. package/dist/session/ac-pass-banking.d.ts +221 -0
  127. package/dist/session/ac-pass-banking.js +761 -0
  128. package/dist/session/active-cli.d.ts +79 -0
  129. package/dist/session/active-cli.js +382 -0
  130. package/dist/session/deposit-sha.d.ts +49 -0
  131. package/dist/session/deposit-sha.js +121 -0
  132. package/dist/session/effort-budget.d.ts +136 -0
  133. package/dist/session/effort-budget.js +352 -0
  134. package/dist/session/index.d.ts +7 -0
  135. package/dist/session/index.js +7 -0
  136. package/dist/session/orientation-compression.d.ts +127 -0
  137. package/dist/session/orientation-compression.js +425 -0
  138. package/dist/session/orientation-state.d.ts +29 -0
  139. package/dist/session/orientation-state.js +85 -0
  140. package/dist/session/session-start.d.ts +31 -0
  141. package/dist/session/session-start.js +228 -2
  142. package/dist/session/toolchain-preflight.d.ts +64 -0
  143. package/dist/session/toolchain-preflight.js +151 -0
  144. package/dist/session/verify-session-ritual.d.ts +14 -0
  145. package/dist/session/verify-session-ritual.js +33 -0
  146. package/dist/story-ready/evaluate.d.ts +11 -0
  147. package/dist/story-ready/evaluate.js +41 -3
  148. package/dist/triage/actions/candidates-log.d.ts +1 -2
  149. package/dist/triage/actions/candidates-log.js +37 -6
  150. package/dist/triage/bootstrap/gitignore.d.ts +1 -1
  151. package/dist/triage/bootstrap/gitignore.js +8 -2
  152. package/dist/triage/bootstrap/index.js +15 -3
  153. package/dist/triage/classify/index.d.ts +1 -0
  154. package/dist/triage/classify/index.js +2 -0
  155. package/dist/triage/classify/label-mirror.js +16 -0
  156. package/dist/triage/classify/mirror-discovery-tip.d.ts +95 -0
  157. package/dist/triage/classify/mirror-discovery-tip.js +234 -0
  158. package/dist/triage/reconcile/reconcile.js +28 -6
  159. package/dist/triage/summary/index.js +12 -4
  160. package/dist/triage/welcome/default-mode.js +16 -0
  161. package/dist/ts-check-lane/run-lane.js +21 -4
  162. package/dist/vbrief-validate/conformance.js +7 -0
  163. package/dist/vitest-runner/coverage-debt-teardown.js +16 -4
  164. package/dist/xbrief-migrate/migrate-project.d.ts +4 -0
  165. package/dist/xbrief-migrate/migrate-project.js +92 -3
  166. package/package.json +15 -3
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Ceremony dial (#3214): ritual depth = f(task size × model tier × project shape).
2
+ * Ceremony dial (#3214 / #3263): ritual depth = f(task size × model tier × project shape).
3
3
  *
4
4
  * Selection policy over existing pieces — not a new subsystem.
5
5
  * Composes:
@@ -7,11 +7,15 @@
7
7
  * - #3014 minimal consumer AGENTS profile (research pointer; not yet a shipped deposit)
8
8
  * - effort estimate (#1581), model routing (#1976/#818), host capability (#1461)
9
9
  *
10
- * Two-stage dial (#3214 design note / #1581 ordering):
11
- * cold-start / incomplete inputs → **rapid** (start light; no plan-item deadlock)
12
- * escalate when evidence arrives (provisional M/L, mid/low tier, full matrix)
10
+ * Two-stage dial (#3214 design note / #1581 ordering) with tier-conditional cold-start (#3263):
11
+ * cold-start / incomplete size → **tier-conditional**:
12
+ * frontier (or unknown tier) rapid; mid/low standard (not rapid)
13
+ * escalate when evidence arrives (provisional M/L size, full matrix)
13
14
  * Full matrix: S × frontier → rapid; non-project → minimal; else scales up.
14
15
  * Override always available via plan.policy.ceremonyDial.override; audited on write.
16
+ *
17
+ * Audit path (#3263): session:start records depth + provisional reasons on
18
+ * `.deft/ritual-state.json` under `ceremony_dial` — use `readCeremonyDialAudit`.
15
19
  */
16
20
  /** Canonical dotted policy field name. */
17
21
  export declare const FIELD_CEREMONY_DIAL = "plan.policy.ceremonyDial";
@@ -60,6 +64,11 @@ export interface CeremonyDialProfile {
60
64
  readonly skipFatPath: boolean;
61
65
  /** How much lifecycle / history write budget this depth intends. */
62
66
  readonly lifecycleWrites: "minimal" | "light" | "full";
67
+ /**
68
+ * Literal acceptance-command verification is always required (#3267 / #3156).
69
+ * Ceremony dial never skips capture+verbatim run — including rapid/minimal.
70
+ */
71
+ readonly literalAcceptanceRequired: true;
63
72
  readonly label: string;
64
73
  }
65
74
  export type CeremonyDialSource = "override" | "matrix" | "default" | "disabled" | "typed" | "default-on-error";
@@ -97,25 +106,38 @@ export declare function normalizeCeremonyTaskSize(raw: unknown): CeremonyTaskSiz
97
106
  export declare function normalizeCeremonyModelTier(raw: unknown): CeremonyModelTier | null;
98
107
  export declare function normalizeCeremonyProjectShape(raw: unknown): CeremonyProjectShape | null;
99
108
  /**
100
- * Two-stage / partial-evidence selection when size or tier is missing (#3214 design note).
109
+ * Tier-conditional cold-start depth when task size is incomplete (#3263).
101
110
  *
102
- * Start light (rapid) on cold incomplete inputs; escalate when partial evidence already
103
- * implies heavier ceremony (apps-bank safety: hard/substantial work must not stay rapid).
104
- * Does not invent plan-item effort (#1581 post-planning only).
111
+ * Mid/low models benefit from structure on hard tasks and should not cold-start
112
+ * at rapid (start-light / escalate-too-late signature). Frontier recovers from a
113
+ * light start. Unknown tier stays rapid (optimistic cold default; pass
114
+ * `--model-tier` / `DEFT_CEREMONY_MODEL_TIER` to unlock the mid/low floor).
115
+ *
116
+ * Escalate-on-evidence still applies when size later arrives (full matrix).
117
+ */
118
+ export declare function selectCeremonyColdStartDepth(modelTier: CeremonyModelTier | null | undefined): CeremonyDepth;
119
+ /**
120
+ * Two-stage / partial-evidence selection when size or tier is missing
121
+ * (#3214 design note / #3263 tier-conditional cold-start).
122
+ *
123
+ * Cold incomplete size is tier-conditional (#3263): mid/low → standard, frontier
124
+ * or unknown → rapid. When size is known without tier, escalate on substantial
125
+ * size (apps-bank safety). Does not invent plan-item effort (#1581 post-planning only).
105
126
  */
106
127
  export declare function selectCeremonyDepthFromPartialEvidence(inputs: {
107
128
  readonly taskSize: CeremonyTaskSize | null;
108
129
  readonly modelTier: CeremonyModelTier | null;
109
130
  }): CeremonyDepth;
110
131
  /**
111
- * Pure default matrix (#3214 acceptance + two-stage design note):
132
+ * Pure default matrix (#3214 acceptance + #3263 tier-conditional cold-start):
112
133
  * - non-project → minimal (#3014 direction)
113
134
  * - S × frontier → rapid (strategies/rapid.md)
114
135
  * - S × mid → standard (mid-tier gains from structure)
115
136
  * - S × low → elevated
116
137
  * - M × low → elevated; M otherwise → standard
117
138
  * - L/XL → elevated (except L × frontier stays standard)
118
- * - Incomplete size/tiertwo-stage partial evidence (default rapid; escalate on M/L or mid/low)
139
+ * - Incomplete size → tier-conditional cold-start (#3263): mid/low standard; frontier/unknown rapid
140
+ * - Size known, tier missing → escalate on M/L (partial evidence)
119
141
  */
120
142
  export declare function selectCeremonyDepthFromMatrix(inputs: CeremonyDialInputs): CeremonyDepth;
121
143
  export interface SelectCeremonyDepthOptions {
@@ -126,7 +148,7 @@ export interface SelectCeremonyDepthOptions {
126
148
  * Deterministic depth selection (pure; no IO).
127
149
  *
128
150
  * Precedence: disabled → standard; override → forced depth; else matrix on inputs;
129
- * empty inputs → **rapid** (two-stage cold default; escalate when evidence arrives).
151
+ * empty inputs → **rapid** (unknown-tier cold default; #3263 mid/low need modelTier set).
130
152
  */
131
153
  export declare function selectCeremonyDepth(options?: SelectCeremonyDepthOptions): CeremonyDialSelection;
132
154
  export interface ResolveCeremonyDialOptions {
@@ -230,4 +252,67 @@ export declare function resolveSessionCeremonyDialInputs(projectRoot: string, ex
230
252
  readonly inputs: CeremonyDialInputs;
231
253
  readonly provisional: ProvisionalCeremonyEstimate;
232
254
  };
255
+ export interface CeremonyDialAuditProvisional {
256
+ readonly taskSize: CeremonyTaskSize | null;
257
+ readonly modelTier: CeremonyModelTier | null;
258
+ readonly projectShape: CeremonyProjectShape | null;
259
+ readonly reasons: readonly string[];
260
+ }
261
+ /**
262
+ * Snapshot of dial selection recorded on `.deft/ritual-state.json` at session:start.
263
+ * Operators audit failed-task depth / provisional reasons without re-running ritual.
264
+ */
265
+ export interface CeremonyDialAuditSnapshot {
266
+ readonly path: string;
267
+ readonly depth: CeremonyDepth | null;
268
+ readonly source: string | null;
269
+ readonly inputs: {
270
+ readonly taskSize: CeremonyTaskSize | null;
271
+ readonly modelTier: CeremonyModelTier | null;
272
+ readonly projectShape: CeremonyProjectShape | null;
273
+ } | null;
274
+ readonly provisional: CeremonyDialAuditProvisional | null;
275
+ readonly raw: Record<string, unknown> | null;
276
+ readonly error: string | null;
277
+ }
278
+ /**
279
+ * Read ceremony dial depth + provisional reasons from ritual-state (#3263 audit path).
280
+ * session:start already writes `ceremony_dial` (incl. provisional) — this is the
281
+ * operator/read path so failed runs can confirm start-light vs escalate timing.
282
+ *
283
+ * Returns `error` when ritual-state is missing/unreadable or lacks `ceremony_dial`;
284
+ * does not throw.
285
+ */
286
+ export declare function readCeremonyDialAudit(projectRoot: string): CeremonyDialAuditSnapshot;
287
+ /** One-line operator summary for audit tooling / failed-task forensics (#3263). */
288
+ export declare function formatCeremonyDialAuditLine(audit: CeremonyDialAuditSnapshot): string;
289
+ /**
290
+ * Reified dial transition for run-summary telemetry (#3282).
291
+ *
292
+ * IMPLEMENTATION PREREQUISITE from the issue: dial transitions must be
293
+ * engine-managed events, not prose-only policy. This function is the CLI-facing
294
+ * transition hook (`policy:set-ceremony-dial` / dial escalate): it persists the
295
+ * override (when confirm) and always emits a `dial_transition` run-summary line
296
+ * when a depth change is applied.
297
+ */
298
+ export interface EscalateCeremonyDialOptions {
299
+ readonly to: CeremonyDepth;
300
+ readonly reason: string;
301
+ readonly evidence?: string;
302
+ readonly sessionId?: string;
303
+ readonly confirm?: boolean;
304
+ readonly actor?: string;
305
+ readonly note?: string;
306
+ /** When false, skip run-summary emission (tests). Default true. */
307
+ readonly emitRunSummary?: boolean;
308
+ readonly env?: NodeJS.ProcessEnv;
309
+ }
310
+ export interface EscalateCeremonyDialResult {
311
+ readonly exitCode: number;
312
+ readonly from: CeremonyDepth | null;
313
+ readonly to: CeremonyDepth;
314
+ readonly changed: boolean;
315
+ readonly lines: readonly string[];
316
+ }
317
+ export declare function escalateCeremonyDial(projectRoot: string, options: EscalateCeremonyDialOptions): EscalateCeremonyDialResult;
233
318
  //# sourceMappingURL=ceremony-dial.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Ceremony dial (#3214): ritual depth = f(task size × model tier × project shape).
2
+ * Ceremony dial (#3214 / #3263): ritual depth = f(task size × model tier × project shape).
3
3
  *
4
4
  * Selection policy over existing pieces — not a new subsystem.
5
5
  * Composes:
@@ -7,14 +7,19 @@
7
7
  * - #3014 minimal consumer AGENTS profile (research pointer; not yet a shipped deposit)
8
8
  * - effort estimate (#1581), model routing (#1976/#818), host capability (#1461)
9
9
  *
10
- * Two-stage dial (#3214 design note / #1581 ordering):
11
- * cold-start / incomplete inputs → **rapid** (start light; no plan-item deadlock)
12
- * escalate when evidence arrives (provisional M/L, mid/low tier, full matrix)
10
+ * Two-stage dial (#3214 design note / #1581 ordering) with tier-conditional cold-start (#3263):
11
+ * cold-start / incomplete size → **tier-conditional**:
12
+ * frontier (or unknown tier) rapid; mid/low standard (not rapid)
13
+ * escalate when evidence arrives (provisional M/L size, full matrix)
13
14
  * Full matrix: S × frontier → rapid; non-project → minimal; else scales up.
14
15
  * Override always available via plan.policy.ceremonyDial.override; audited on write.
16
+ *
17
+ * Audit path (#3263): session:start records depth + provisional reasons on
18
+ * `.deft/ritual-state.json` under `ceremony_dial` — use `readCeremonyDialAudit`.
15
19
  */
16
20
  import { existsSync, readFileSync, statSync } from "node:fs";
17
21
  import { join } from "node:path";
22
+ import { RunSummaryEmitter } from "../run-summary/emit.js";
18
23
  import { atomicWriteProjectDefinition, projectDefinitionMutationLock, } from "../vbrief-build/project-definition-io.js";
19
24
  import { migrateLegacyPolicyKey, PLAN_POLICY_KEY, readPlanPolicy } from "./plan-extensions.js";
20
25
  import { policyColonInvocation } from "./policy-invocation.js";
@@ -45,6 +50,9 @@ export const CEREMONY_MINIMAL_AGENTS_PROFILE_POINTER = "docs/analysis/2026-07-31
45
50
  * (`verify:session-ritual --tier=gated`). Gated verify treats
46
51
  * `deferred_reason` as satisfied, so dial-driven deferral would skip gates.
47
52
  * ! `verify_tools` also remains required on every dial depth (not skipFatPath).
53
+ * ! Literal acceptance-command verification (#3267) is required at every depth
54
+ * (`literalAcceptanceRequired: true`), including rapid/minimal — capture exact
55
+ * stated commands at intake and run them verbatim before done. Extends #973.
48
56
  * ~ Rapid/minimal MAY lighten informational cold path only: triage welcome,
49
57
  * optional network/release probe, staleness tickler.
50
58
  */
@@ -55,6 +63,7 @@ const PROFILES = {
55
63
  autoDeferSteps: ["triage_welcome"],
56
64
  skipFatPath: true,
57
65
  lifecycleWrites: "minimal",
66
+ literalAcceptanceRequired: true,
58
67
  label: "minimal (non-project / #3014 direction)",
59
68
  },
60
69
  rapid: {
@@ -62,6 +71,7 @@ const PROFILES = {
62
71
  autoDeferSteps: ["triage_welcome"],
63
72
  skipFatPath: true,
64
73
  lifecycleWrites: "light",
74
+ literalAcceptanceRequired: true,
65
75
  label: "rapid (strategies/rapid.md light path)",
66
76
  },
67
77
  standard: {
@@ -69,6 +79,7 @@ const PROFILES = {
69
79
  autoDeferSteps: [],
70
80
  skipFatPath: false,
71
81
  lifecycleWrites: "full",
82
+ literalAcceptanceRequired: true,
72
83
  label: "standard (full session ritual)",
73
84
  },
74
85
  elevated: {
@@ -76,6 +87,7 @@ const PROFILES = {
76
87
  autoDeferSteps: [],
77
88
  skipFatPath: false,
78
89
  lifecycleWrites: "full",
90
+ literalAcceptanceRequired: true,
79
91
  label: "elevated (full ritual; prefer more gates for weaker tiers / large tasks)",
80
92
  },
81
93
  };
@@ -186,11 +198,29 @@ export function normalizeCeremonyProjectShape(raw) {
186
198
  return null;
187
199
  }
188
200
  /**
189
- * Two-stage / partial-evidence selection when size or tier is missing (#3214 design note).
201
+ * Tier-conditional cold-start depth when task size is incomplete (#3263).
202
+ *
203
+ * Mid/low models benefit from structure on hard tasks and should not cold-start
204
+ * at rapid (start-light / escalate-too-late signature). Frontier recovers from a
205
+ * light start. Unknown tier stays rapid (optimistic cold default; pass
206
+ * `--model-tier` / `DEFT_CEREMONY_MODEL_TIER` to unlock the mid/low floor).
207
+ *
208
+ * Escalate-on-evidence still applies when size later arrives (full matrix).
209
+ */
210
+ export function selectCeremonyColdStartDepth(modelTier) {
211
+ if (modelTier === "mid" || modelTier === "low") {
212
+ return "standard";
213
+ }
214
+ // frontier or unknown → rapid
215
+ return "rapid";
216
+ }
217
+ /**
218
+ * Two-stage / partial-evidence selection when size or tier is missing
219
+ * (#3214 design note / #3263 tier-conditional cold-start).
190
220
  *
191
- * Start light (rapid) on cold incomplete inputs; escalate when partial evidence already
192
- * implies heavier ceremony (apps-bank safety: hard/substantial work must not stay rapid).
193
- * Does not invent plan-item effort (#1581 post-planning only).
221
+ * Cold incomplete size is tier-conditional (#3263): mid/low standard, frontier
222
+ * or unknown rapid. When size is known without tier, escalate on substantial
223
+ * size (apps-bank safety). Does not invent plan-item effort (#1581 post-planning only).
194
224
  */
195
225
  export function selectCeremonyDepthFromPartialEvidence(inputs) {
196
226
  const size = inputs.taskSize;
@@ -203,26 +233,20 @@ export function selectCeremonyDepthFromPartialEvidence(inputs) {
203
233
  return "standard";
204
234
  return "elevated"; // L / XL
205
235
  }
206
- // Tier known, size unknown mid/low need structure; frontier can start light.
207
- if (size === null && tier !== null) {
208
- if (tier === "frontier")
209
- return "rapid";
210
- if (tier === "mid")
211
- return "standard";
212
- return "elevated"; // low
213
- }
214
- // Both unknown: two-stage cold default.
215
- return "rapid";
236
+ // Size incomplete (null), any tier including unknown: tier-conditional cold-start (#3263).
237
+ // Callers with both size and tier set use the full matrix instead.
238
+ return selectCeremonyColdStartDepth(tier);
216
239
  }
217
240
  /**
218
- * Pure default matrix (#3214 acceptance + two-stage design note):
241
+ * Pure default matrix (#3214 acceptance + #3263 tier-conditional cold-start):
219
242
  * - non-project → minimal (#3014 direction)
220
243
  * - S × frontier → rapid (strategies/rapid.md)
221
244
  * - S × mid → standard (mid-tier gains from structure)
222
245
  * - S × low → elevated
223
246
  * - M × low → elevated; M otherwise → standard
224
247
  * - L/XL → elevated (except L × frontier stays standard)
225
- * - Incomplete size/tiertwo-stage partial evidence (default rapid; escalate on M/L or mid/low)
248
+ * - Incomplete size → tier-conditional cold-start (#3263): mid/low standard; frontier/unknown rapid
249
+ * - Size known, tier missing → escalate on M/L (partial evidence)
226
250
  */
227
251
  export function selectCeremonyDepthFromMatrix(inputs) {
228
252
  const shape = inputs.projectShape ?? null;
@@ -279,7 +303,7 @@ function parseConfig(raw) {
279
303
  * Deterministic depth selection (pure; no IO).
280
304
  *
281
305
  * Precedence: disabled → standard; override → forced depth; else matrix on inputs;
282
- * empty inputs → **rapid** (two-stage cold default; escalate when evidence arrives).
306
+ * empty inputs → **rapid** (unknown-tier cold default; #3263 mid/low need modelTier set).
283
307
  */
284
308
  export function selectCeremonyDepth(options = {}) {
285
309
  const config = {
@@ -317,8 +341,8 @@ export function selectCeremonyDepth(options = {}) {
317
341
  }
318
342
  const hasAnyInput = inputs.taskSize !== null || inputs.modelTier !== null || inputs.projectShape !== null;
319
343
  if (!hasAnyInput) {
320
- // Two-stage dial cold default (#3214 design note / #1581 ordering).
321
- const depth = "rapid";
344
+ // Unknown-tier cold default (#3214 / #3263): rapid until modelTier or size arrives.
345
+ const depth = selectCeremonyColdStartDepth(null);
322
346
  return {
323
347
  depth,
324
348
  source: "default",
@@ -408,6 +432,7 @@ export function ceremonyDialToDict(selection) {
408
432
  autoDeferSteps: [...selection.profile.autoDeferSteps],
409
433
  skipFatPath: selection.profile.skipFatPath,
410
434
  lifecycleWrites: selection.profile.lifecycleWrites,
435
+ literalAcceptanceRequired: selection.profile.literalAcceptanceRequired,
411
436
  label: selection.profile.label,
412
437
  },
413
438
  composition: {
@@ -826,4 +851,206 @@ export function resolveSessionCeremonyDialInputs(projectRoot, explicit, options
826
851
  provisional,
827
852
  };
828
853
  }
854
+ function asOptionalDepth(value) {
855
+ return isCeremonyDepth(value) ? value : null;
856
+ }
857
+ function asOptionalTaskSize(value) {
858
+ return isTaskSize(value) ? value : null;
859
+ }
860
+ function asOptionalModelTier(value) {
861
+ return isModelTier(value) ? value : null;
862
+ }
863
+ function asOptionalProjectShape(value) {
864
+ return isProjectShape(value) ? value : null;
865
+ }
866
+ /**
867
+ * Read ceremony dial depth + provisional reasons from ritual-state (#3263 audit path).
868
+ * session:start already writes `ceremony_dial` (incl. provisional) — this is the
869
+ * operator/read path so failed runs can confirm start-light vs escalate timing.
870
+ *
871
+ * Returns `error` when ritual-state is missing/unreadable or lacks `ceremony_dial`;
872
+ * does not throw.
873
+ */
874
+ export function readCeremonyDialAudit(projectRoot) {
875
+ const path = join(projectRoot, ".deft", "ritual-state.json");
876
+ const empty = (error) => ({
877
+ path,
878
+ depth: null,
879
+ source: null,
880
+ inputs: null,
881
+ provisional: null,
882
+ raw: null,
883
+ error,
884
+ });
885
+ try {
886
+ if (!existsSync(path) || !statSync(path).isFile()) {
887
+ return empty(`ritual-state missing at ${path}`);
888
+ }
889
+ }
890
+ catch (exc) {
891
+ return empty(`ritual-state unreadable at ${path}: ${String(exc)}`);
892
+ }
893
+ let payload;
894
+ try {
895
+ payload = JSON.parse(readFileSync(path, { encoding: "utf8" }));
896
+ }
897
+ catch (exc) {
898
+ if (exc instanceof SyntaxError) {
899
+ return empty(`ritual-state is not valid JSON: ${exc.message}`);
900
+ }
901
+ return empty(`ritual-state cannot be read: ${String(exc)}`);
902
+ }
903
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
904
+ return empty("ritual-state top-level value must be an object");
905
+ }
906
+ const root = payload;
907
+ const dialRaw = root.ceremony_dial;
908
+ if (dialRaw === undefined || dialRaw === null) {
909
+ return empty("ritual-state has no ceremony_dial field (pre-#3214 or non-mutation session)");
910
+ }
911
+ if (typeof dialRaw !== "object" || Array.isArray(dialRaw)) {
912
+ return empty("ritual-state ceremony_dial must be an object");
913
+ }
914
+ const dial = dialRaw;
915
+ const depth = asOptionalDepth(dial.depth);
916
+ const source = typeof dial.source === "string" ? dial.source : null;
917
+ let inputs = null;
918
+ const inputsRaw = dial.inputs;
919
+ if (typeof inputsRaw === "object" && inputsRaw !== null && !Array.isArray(inputsRaw)) {
920
+ const rec = inputsRaw;
921
+ inputs = {
922
+ taskSize: asOptionalTaskSize(rec.taskSize),
923
+ modelTier: asOptionalModelTier(rec.modelTier),
924
+ projectShape: asOptionalProjectShape(rec.projectShape),
925
+ };
926
+ }
927
+ let provisional = null;
928
+ const provRaw = dial.provisional;
929
+ if (typeof provRaw === "object" && provRaw !== null && !Array.isArray(provRaw)) {
930
+ const rec = provRaw;
931
+ const reasons = Array.isArray(rec.reasons)
932
+ ? rec.reasons.filter((r) => typeof r === "string")
933
+ : [];
934
+ provisional = {
935
+ taskSize: asOptionalTaskSize(rec.taskSize),
936
+ modelTier: asOptionalModelTier(rec.modelTier),
937
+ projectShape: asOptionalProjectShape(rec.projectShape),
938
+ reasons,
939
+ };
940
+ }
941
+ return {
942
+ path,
943
+ depth,
944
+ source,
945
+ inputs,
946
+ provisional,
947
+ raw: { ...dial },
948
+ error: null,
949
+ };
950
+ }
951
+ /** Collapse whitespace so operator audit lines stay single-line (Greptile P2 #3263). */
952
+ function oneLineAuditToken(value) {
953
+ return value
954
+ .replace(/[\r\n\t]+/g, " ")
955
+ .replace(/ {2,}/g, " ")
956
+ .trim();
957
+ }
958
+ /** One-line operator summary for audit tooling / failed-task forensics (#3263). */
959
+ export function formatCeremonyDialAuditLine(audit) {
960
+ if (audit.error !== null) {
961
+ return `[deft ceremony-dial audit] error=${oneLineAuditToken(audit.error)}`;
962
+ }
963
+ const parts = [
964
+ `[deft ceremony-dial audit] depth=${audit.depth ?? "-"}`,
965
+ `source=${audit.source ?? "-"}`,
966
+ `taskSize=${audit.inputs?.taskSize ?? "-"}`,
967
+ `modelTier=${audit.inputs?.modelTier ?? "-"}`,
968
+ `projectShape=${audit.inputs?.projectShape ?? "-"}`,
969
+ ];
970
+ if (audit.provisional !== null) {
971
+ const reasons = audit.provisional.reasons.length > 0
972
+ ? audit.provisional.reasons
973
+ .map(oneLineAuditToken)
974
+ .filter((r) => r.length > 0)
975
+ .join("; ")
976
+ : "(none)";
977
+ parts.push(`provisional.reasons=${reasons.length > 0 ? reasons : "(none)"}`);
978
+ }
979
+ return parts.join(" ");
980
+ }
981
+ export function escalateCeremonyDial(projectRoot, options) {
982
+ const prior = resolveCeremonyDial(projectRoot);
983
+ const from = prior.depth;
984
+ if (options.confirm !== true) {
985
+ return {
986
+ exitCode: 1,
987
+ from,
988
+ to: options.to,
989
+ changed: false,
990
+ lines: [
991
+ "Ceremony dial escalate changes ritual depth for future session:start.",
992
+ " Re-run with --confirm to apply.",
993
+ ` Proposed: ${from} -> ${options.to} (reason: ${oneLineAuditToken(options.reason)})`,
994
+ ],
995
+ };
996
+ }
997
+ const setResult = setCeremonyDial(projectRoot, {
998
+ override: options.to,
999
+ confirm: true,
1000
+ actor: options.actor ?? policyColonInvocation("set-ceremony-dial"),
1001
+ note: options.note ?? `escalate: ${options.reason}`,
1002
+ });
1003
+ if (setResult.exitCode !== 0) {
1004
+ return {
1005
+ exitCode: setResult.exitCode,
1006
+ from,
1007
+ to: options.to,
1008
+ changed: false,
1009
+ lines: setResult.stdout
1010
+ .split("\n")
1011
+ .map((l) => l.trimEnd())
1012
+ .filter((l) => l.length > 0),
1013
+ };
1014
+ }
1015
+ // #3282: event-driven dial_transition line (fail-open).
1016
+ if (options.emitRunSummary !== false) {
1017
+ try {
1018
+ const audit = readCeremonyDialAudit(projectRoot);
1019
+ const rawSid = audit.raw?.session_id;
1020
+ const sid = options.sessionId ??
1021
+ (typeof rawSid === "string" && rawSid.length > 0
1022
+ ? rawSid
1023
+ : `dial-${Date.now().toString(36)}`);
1024
+ const emitter = new RunSummaryEmitter({
1025
+ projectRoot,
1026
+ sessionId: sid,
1027
+ env: options.env,
1028
+ });
1029
+ emitter.emitDialTransition({
1030
+ from,
1031
+ to: options.to,
1032
+ reason: options.reason,
1033
+ evidence: options.evidence,
1034
+ });
1035
+ }
1036
+ catch {
1037
+ // fail-open
1038
+ }
1039
+ }
1040
+ return {
1041
+ exitCode: 0,
1042
+ from,
1043
+ to: options.to,
1044
+ changed: setResult.changed || from !== options.to,
1045
+ lines: [
1046
+ `✓ ceremony dial escalate: ${from} -> ${options.to}`,
1047
+ ` reason: ${oneLineAuditToken(options.reason)}`,
1048
+ ...(options.evidence ? [` evidence: ${oneLineAuditToken(options.evidence)}`] : []),
1049
+ ...setResult.stdout
1050
+ .split("\n")
1051
+ .map((l) => l.trimEnd())
1052
+ .filter((l) => l.length > 0),
1053
+ ],
1054
+ };
1055
+ }
829
1056
  //# sourceMappingURL=ceremony-dial.js.map
@@ -1,3 +1,4 @@
1
+ export * from "./ac-pass-banking.js";
1
2
  export * from "./agents-md-advisory.js";
2
3
  export * from "./autonomy.js";
3
4
  export * from "./capacity.js";
@@ -13,6 +14,7 @@ export * from "./host-hooks.js";
13
14
  export * from "./host-slash-commands.js";
14
15
  export * from "./hotfix-criteria.js";
15
16
  export * from "./intent-ceiling.js";
17
+ export * from "./merge-approval-head.js";
16
18
  export * from "./min-greptile-confidence.js";
17
19
  export * from "./no-deft-directive.js";
18
20
  export * from "./org-force-on-migration.js";
@@ -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,6 +17,7 @@ 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";
@@ -31,6 +33,7 @@ export * from "./host-hooks.js";
31
33
  export * from "./host-slash-commands.js";
32
34
  export * from "./hotfix-criteria.js";
33
35
  export * from "./intent-ceiling.js";
36
+ export * from "./merge-approval-head.js";
34
37
  export * from "./min-greptile-confidence.js";
35
38
  export * from "./no-deft-directive.js";
36
39
  export * from "./org-force-on-migration.js";
@@ -419,6 +422,15 @@ function inspectCeremonyDialField(data, projectRoot) {
419
422
  source: field.source,
420
423
  };
421
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
+ }
422
434
  const REGISTERED_POLICIES = [
423
435
  inspectAllowDirectCommits,
424
436
  inspectWipCap,
@@ -447,6 +459,7 @@ const REGISTERED_POLICIES = [
447
459
  inspectRequireHumanMergeField,
448
460
  inspectHotfixCriteriaField,
449
461
  inspectCeremonyDialField,
462
+ inspectAcPassBankingField,
450
463
  ];
451
464
  /** Walk registered inspectors and return one row per field (#1148). */
452
465
  export function inspectAllPolicies(projectRoot) {
@@ -485,7 +498,9 @@ export function inspectOnePolicy(name, projectRoot) {
485
498
  ? FIELD_MIN_GREPTILE_CONFIDENCE
486
499
  : name === FIELD_CEREMONY_DIAL_CLI_ALIAS
487
500
  ? FIELD_CEREMONY_DIAL
488
- : name;
501
+ : name === FIELD_AC_PASS_BANKING_CLI_ALIAS
502
+ ? FIELD_AC_PASS_BANKING
503
+ : name;
489
504
  for (const field of inspectAllPolicies(projectRoot)) {
490
505
  if (field.name === normalized)
491
506
  return field;