@deftai/directive-core 0.100.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.
- package/dist/authz/classify.js +100 -23
- package/dist/authz/decompose-apply.d.ts +14 -0
- package/dist/authz/decompose-apply.js +93 -18
- package/dist/check/cached-orchestrator.d.ts +26 -5
- package/dist/check/cached-orchestrator.js +228 -6
- package/dist/check/gate-lists.d.ts +10 -4
- package/dist/check/gate-lists.js +19 -5
- package/dist/check/index.d.ts +3 -2
- package/dist/check/index.js +2 -1
- package/dist/check/named-cause.d.ts +45 -0
- package/dist/check/named-cause.js +121 -0
- package/dist/check/orchestrator.js +6 -1
- package/dist/doctor/help.d.ts +5 -0
- package/dist/doctor/help.js +31 -0
- package/dist/doctor/index.d.ts +2 -0
- package/dist/doctor/index.js +2 -0
- package/dist/doctor/main.js +58 -0
- package/dist/doctor/session-coda.d.ts +82 -0
- package/dist/doctor/session-coda.js +151 -0
- package/dist/doctor/types.d.ts +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/gitignore.js +2 -0
- package/dist/intake/issue-ingest.js +7 -0
- package/dist/policy/ac-pass-banking.d.ts +58 -0
- package/dist/policy/ac-pass-banking.js +150 -0
- package/dist/policy/ceremony-dial.d.ts +29 -0
- package/dist/policy/ceremony-dial.js +76 -0
- package/dist/policy/index.d.ts +1 -0
- package/dist/policy/index.js +15 -1
- package/dist/preflight-cache/evaluate.d.ts +3 -0
- package/dist/preflight-cache/evaluate.js +3 -0
- package/dist/product-first-done-gate/acceptance.d.ts +25 -0
- package/dist/product-first-done-gate/acceptance.js +247 -0
- package/dist/product-first-done-gate/check-mode.d.ts +45 -0
- package/dist/product-first-done-gate/check-mode.js +148 -0
- package/dist/product-first-done-gate/evaluate.d.ts +50 -0
- package/dist/product-first-done-gate/evaluate.js +255 -0
- package/dist/product-first-done-gate/index.d.ts +11 -0
- package/dist/product-first-done-gate/index.js +11 -0
- package/dist/product-first-done-gate/types.d.ts +64 -0
- package/dist/product-first-done-gate/types.js +61 -0
- package/dist/run-summary/emit.d.ts +56 -0
- package/dist/run-summary/emit.js +171 -0
- package/dist/run-summary/index.d.ts +4 -0
- package/dist/run-summary/index.js +4 -0
- package/dist/run-summary/path.d.ts +25 -0
- package/dist/run-summary/path.js +78 -0
- package/dist/run-summary/types.d.ts +76 -0
- package/dist/run-summary/types.js +21 -0
- package/dist/scope/acceptance-evidence.d.ts +34 -0
- package/dist/scope/acceptance-evidence.js +84 -10
- package/dist/scope/decompose.d.ts +5 -0
- package/dist/scope/decompose.js +11 -2
- package/dist/session/ac-pass-banking.d.ts +221 -0
- package/dist/session/ac-pass-banking.js +761 -0
- package/dist/session/deposit-sha.d.ts +49 -0
- package/dist/session/deposit-sha.js +121 -0
- package/dist/session/effort-budget.d.ts +6 -0
- package/dist/session/effort-budget.js +21 -3
- package/dist/session/index.d.ts +5 -0
- package/dist/session/index.js +5 -0
- package/dist/session/orientation-compression.d.ts +127 -0
- package/dist/session/orientation-compression.js +425 -0
- package/dist/session/orientation-state.d.ts +29 -0
- package/dist/session/orientation-state.js +85 -0
- package/dist/session/session-start.d.ts +25 -0
- package/dist/session/session-start.js +175 -0
- package/dist/session/toolchain-preflight.d.ts +64 -0
- package/dist/session/toolchain-preflight.js +151 -0
- package/dist/triage/bootstrap/gitignore.d.ts +1 -1
- package/dist/triage/bootstrap/gitignore.js +8 -2
- package/dist/triage/bootstrap/index.js +15 -3
- package/dist/triage/classify/index.d.ts +1 -0
- package/dist/triage/classify/index.js +2 -0
- package/dist/triage/classify/label-mirror.js +16 -0
- package/dist/triage/classify/mirror-discovery-tip.d.ts +95 -0
- package/dist/triage/classify/mirror-discovery-tip.js +234 -0
- package/dist/triage/reconcile/reconcile.js +28 -6
- package/dist/triage/summary/index.js +12 -4
- package/dist/triage/welcome/default-mode.js +16 -0
- package/dist/ts-check-lane/run-lane.js +21 -4
- package/dist/vbrief-validate/conformance.js +7 -0
- package/dist/vitest-runner/coverage-debt-teardown.js +16 -4
- package/package.json +11 -3
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve where run-summary JSONL should go (#3282 emission matrix).
|
|
3
|
+
*
|
|
4
|
+
* - `DEFT_RUN_SUMMARY_PATH=<path>` → append JSONL there (explicit; warn once on write fail)
|
|
5
|
+
* - `DEFT_RUN_SUMMARY_PATH=-` → stdout lines prefixed `DEFT-TLM:`
|
|
6
|
+
* - unset → repo-root `.deft-run-summary.json` only when .gitignore covers it; else silent
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
10
|
+
import { DEFAULT_RUN_SUMMARY_BASENAME, ENV_RUN_SUMMARY_PATH, } from "./types.js";
|
|
11
|
+
export { DEFAULT_RUN_SUMMARY_BASENAME, ENV_RUN_SUMMARY_PATH, RUN_SUMMARY_STDOUT_PREFIX, RUN_SUMMARY_WRITE_WARNING, } from "./types.js";
|
|
12
|
+
/**
|
|
13
|
+
* True when a .gitignore line covers the default run-summary basename.
|
|
14
|
+
* Matches exact line or trailing slash variants; ignores comments.
|
|
15
|
+
*/
|
|
16
|
+
export function gitignoreCoversRunSummary(projectRoot, basename = DEFAULT_RUN_SUMMARY_BASENAME) {
|
|
17
|
+
const giPath = join(projectRoot, ".gitignore");
|
|
18
|
+
if (!existsSync(giPath)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
let text;
|
|
22
|
+
try {
|
|
23
|
+
text = readFileSync(giPath, "utf8");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const targets = new Set([basename, basename.replace(/^\.\//, "")]);
|
|
29
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
30
|
+
const line = raw.trim();
|
|
31
|
+
if (line.length === 0 || line.startsWith("#"))
|
|
32
|
+
continue;
|
|
33
|
+
// Strip trailing inline comments carefully (space + #).
|
|
34
|
+
const bare = line.replace(/\s+#.*$/, "").trim();
|
|
35
|
+
if (targets.has(bare) || targets.has(bare.replace(/^\//, ""))) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve emission destination for the run-summary matrix (#3282).
|
|
43
|
+
* Never throws — fail-open consumers treat resolution errors as silent.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveRunSummaryDestination(projectRoot, options = {}) {
|
|
46
|
+
try {
|
|
47
|
+
const env = options.env ?? process.env;
|
|
48
|
+
const raw = env[ENV_RUN_SUMMARY_PATH];
|
|
49
|
+
if (raw !== undefined && raw.trim() === "-") {
|
|
50
|
+
return { kind: "stdout" };
|
|
51
|
+
}
|
|
52
|
+
if (raw !== undefined && raw.trim().length > 0) {
|
|
53
|
+
const trimmed = raw.trim();
|
|
54
|
+
const path = isAbsolute(trimmed) ? resolve(trimmed) : resolve(projectRoot, trimmed);
|
|
55
|
+
return {
|
|
56
|
+
kind: "file",
|
|
57
|
+
path,
|
|
58
|
+
truncateOnSessionStart: false,
|
|
59
|
+
explicit: true,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Unset: default path only with gitignore coverage.
|
|
63
|
+
const covers = options.gitignoreCovers?.(projectRoot) ?? gitignoreCoversRunSummary(projectRoot);
|
|
64
|
+
if (!covers) {
|
|
65
|
+
return { kind: "silent" };
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
kind: "file",
|
|
69
|
+
path: resolve(projectRoot, DEFAULT_RUN_SUMMARY_BASENAME),
|
|
70
|
+
truncateOnSessionStart: true,
|
|
71
|
+
explicit: false,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return { kind: "silent" };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=path.js.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run-summary telemetry types (#3282).
|
|
3
|
+
*
|
|
4
|
+
* Event-driven JSONL lines for harness collection. Silent by default unless
|
|
5
|
+
* `DEFT_RUN_SUMMARY_PATH` is set (or the gitignored default path is writable).
|
|
6
|
+
*/
|
|
7
|
+
export declare const RUN_SUMMARY_SCHEMA_VERSION: 1;
|
|
8
|
+
/** Env var that opts into / redirects run-summary JSONL (#3282). */
|
|
9
|
+
export declare const ENV_RUN_SUMMARY_PATH = "DEFT_RUN_SUMMARY_PATH";
|
|
10
|
+
/** Repo-root default collectible path when gitignore coverage is present. */
|
|
11
|
+
export declare const DEFAULT_RUN_SUMMARY_BASENAME = ".deft-run-summary.json";
|
|
12
|
+
/** Prefix for stdout lines when `DEFT_RUN_SUMMARY_PATH=-`. */
|
|
13
|
+
export declare const RUN_SUMMARY_STDOUT_PREFIX = "DEFT-TLM:";
|
|
14
|
+
/** One warning when an explicitly requested write fails. */
|
|
15
|
+
export declare const RUN_SUMMARY_WRITE_WARNING = "[deft run-summary] failed to write DEFT_RUN_SUMMARY_PATH telemetry (fail-open; exit codes unchanged)";
|
|
16
|
+
export declare const RUN_SUMMARY_EVENT_KINDS: readonly ["session_start", "dial_transition", "check_invocation"];
|
|
17
|
+
export type RunSummaryEventKind = (typeof RUN_SUMMARY_EVENT_KINDS)[number];
|
|
18
|
+
export interface RunSummaryBaseFields {
|
|
19
|
+
readonly schema_version: typeof RUN_SUMMARY_SCHEMA_VERSION;
|
|
20
|
+
readonly session_id: string;
|
|
21
|
+
readonly framework_version: string;
|
|
22
|
+
/** Monotonic per-emitter sequence (1-based). */
|
|
23
|
+
readonly seq: number;
|
|
24
|
+
readonly ts: string;
|
|
25
|
+
readonly event: RunSummaryEventKind;
|
|
26
|
+
}
|
|
27
|
+
export interface SessionStartRunSummaryPayload {
|
|
28
|
+
readonly ceremony_dial?: Record<string, unknown>;
|
|
29
|
+
readonly preflight?: Record<string, unknown>;
|
|
30
|
+
readonly ceremony_tier?: string;
|
|
31
|
+
readonly ready?: boolean;
|
|
32
|
+
readonly exit_code?: number;
|
|
33
|
+
/** #3286: orientation surfaces composed into session:start (graduation trigger). */
|
|
34
|
+
readonly orientation_call_count?: number;
|
|
35
|
+
readonly orientation_compact?: boolean;
|
|
36
|
+
readonly deposit_sha?: string;
|
|
37
|
+
readonly orientation_later_status?: string;
|
|
38
|
+
readonly orientation_sections?: readonly Record<string, unknown>[];
|
|
39
|
+
}
|
|
40
|
+
export interface DialTransitionRunSummaryPayload {
|
|
41
|
+
readonly from: string | null;
|
|
42
|
+
readonly to: string;
|
|
43
|
+
readonly reason: string;
|
|
44
|
+
readonly evidence?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface CheckGateOutcome {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
readonly status: "run" | "skipped" | "failed";
|
|
49
|
+
readonly exit_code?: number;
|
|
50
|
+
readonly cause?: string;
|
|
51
|
+
readonly remedy?: string;
|
|
52
|
+
readonly from_cache?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface CheckInvocationRunSummaryPayload {
|
|
55
|
+
readonly target: string;
|
|
56
|
+
readonly exit_code: number;
|
|
57
|
+
readonly degraded?: boolean;
|
|
58
|
+
readonly gates: readonly CheckGateOutcome[];
|
|
59
|
+
}
|
|
60
|
+
export type RunSummaryPayload = SessionStartRunSummaryPayload | DialTransitionRunSummaryPayload | CheckInvocationRunSummaryPayload;
|
|
61
|
+
export type RunSummaryLine = RunSummaryBaseFields & {
|
|
62
|
+
readonly payload: RunSummaryPayload;
|
|
63
|
+
};
|
|
64
|
+
export type RunSummaryDestination = {
|
|
65
|
+
readonly kind: "silent";
|
|
66
|
+
} | {
|
|
67
|
+
readonly kind: "stdout";
|
|
68
|
+
} | {
|
|
69
|
+
readonly kind: "file";
|
|
70
|
+
readonly path: string;
|
|
71
|
+
/** Truncate default-path file on session_start only. */
|
|
72
|
+
readonly truncateOnSessionStart: boolean;
|
|
73
|
+
/** Explicit path (env set) vs default gitignored path. */
|
|
74
|
+
readonly explicit: boolean;
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run-summary telemetry types (#3282).
|
|
3
|
+
*
|
|
4
|
+
* Event-driven JSONL lines for harness collection. Silent by default unless
|
|
5
|
+
* `DEFT_RUN_SUMMARY_PATH` is set (or the gitignored default path is writable).
|
|
6
|
+
*/
|
|
7
|
+
export const RUN_SUMMARY_SCHEMA_VERSION = 1;
|
|
8
|
+
/** Env var that opts into / redirects run-summary JSONL (#3282). */
|
|
9
|
+
export const ENV_RUN_SUMMARY_PATH = "DEFT_RUN_SUMMARY_PATH";
|
|
10
|
+
/** Repo-root default collectible path when gitignore coverage is present. */
|
|
11
|
+
export const DEFAULT_RUN_SUMMARY_BASENAME = ".deft-run-summary.json";
|
|
12
|
+
/** Prefix for stdout lines when `DEFT_RUN_SUMMARY_PATH=-`. */
|
|
13
|
+
export const RUN_SUMMARY_STDOUT_PREFIX = "DEFT-TLM:";
|
|
14
|
+
/** One warning when an explicitly requested write fails. */
|
|
15
|
+
export const RUN_SUMMARY_WRITE_WARNING = "[deft run-summary] failed to write DEFT_RUN_SUMMARY_PATH telemetry (fail-open; exit codes unchanged)";
|
|
16
|
+
export const RUN_SUMMARY_EVENT_KINDS = [
|
|
17
|
+
"session_start",
|
|
18
|
+
"dial_transition",
|
|
19
|
+
"check_invocation",
|
|
20
|
+
];
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -5,8 +5,18 @@
|
|
|
5
5
|
* plan item needs either typed evidence or a human-origin disposition before complete
|
|
6
6
|
* may advance it. Kind suitability: merge/review alone cannot satisfy smoke, UAT,
|
|
7
7
|
* deploy, or observed_behavior requirements.
|
|
8
|
+
*
|
|
9
|
+
* Canonical item keys are namespaced under #1620 / #3305 (Option B):
|
|
10
|
+
* - plan.items[].x-directive/evidence
|
|
11
|
+
* - plan.items[].x-directive/disposition
|
|
12
|
+
* Bare `evidence` / `disposition` are not valid typed evidence (no dual-read).
|
|
13
|
+
* ITEM_CORE is not expanded with bare keys; verify:vbrief-conformance rejects them.
|
|
8
14
|
*/
|
|
9
15
|
import type { GrantOrigin } from "../authz/types.js";
|
|
16
|
+
/** Canonical namespaced key for typed acceptance evidence (#3305 / #1620). */
|
|
17
|
+
export declare const ACCEPTANCE_EVIDENCE_KEY: "x-directive/evidence";
|
|
18
|
+
/** Canonical namespaced key for human-origin disposition (#3305 / #1620). */
|
|
19
|
+
export declare const ACCEPTANCE_DISPOSITION_KEY: "x-directive/disposition";
|
|
10
20
|
/** Closed evidence kinds (locked Q3). */
|
|
11
21
|
export declare const ACCEPTANCE_EVIDENCE_KINDS: readonly ["test", "review", "merge", "deploy", "smoke", "uat", "observed_behavior"];
|
|
12
22
|
export type AcceptanceEvidenceKind = (typeof ACCEPTANCE_EVIDENCE_KINDS)[number];
|
|
@@ -64,6 +74,30 @@ export declare function inferRequiredStrictAxes(item: Record<string, unknown>):
|
|
|
64
74
|
* or record a human-origin disposition (#3240 Greptile P1).
|
|
65
75
|
*/
|
|
66
76
|
export declare function isEvidenceKindSuitable(kind: AcceptanceEvidenceKind, requiredAxes: readonly StrictAcceptanceAxis[]): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Read only namespaced acceptance fields (#3305). Bare `evidence` / `disposition`
|
|
79
|
+
* are never treated as success (no permanent dual-read).
|
|
80
|
+
*/
|
|
81
|
+
export declare function readNamespacedAcceptanceFields(item: Record<string, unknown>): {
|
|
82
|
+
readonly evidence: unknown;
|
|
83
|
+
readonly disposition: unknown;
|
|
84
|
+
readonly hasEvidence: boolean;
|
|
85
|
+
readonly hasDisposition: boolean;
|
|
86
|
+
readonly hasBareEvidence: boolean;
|
|
87
|
+
readonly hasBareDisposition: boolean;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Stamp typed evidence under the canonical namespaced key only.
|
|
91
|
+
* Clears bare evidence/disposition and any prior namespaced disposition so the item
|
|
92
|
+
* cannot carry both acceptance fields after a replace (#3305 Greptile P2).
|
|
93
|
+
*/
|
|
94
|
+
export declare function stampNamespacedEvidence(item: Record<string, unknown>, record: AcceptanceEvidenceRecord): void;
|
|
95
|
+
/**
|
|
96
|
+
* Stamp human-origin disposition under the canonical namespaced key only.
|
|
97
|
+
* Clears bare evidence/disposition and any prior namespaced evidence so the item
|
|
98
|
+
* cannot carry both acceptance fields after a replace (#3305 Greptile P2).
|
|
99
|
+
*/
|
|
100
|
+
export declare function stampNamespacedDisposition(item: Record<string, unknown>, record: AcceptanceDispositionRecord): void;
|
|
67
101
|
/**
|
|
68
102
|
* Fail closed when any non-terminal plan item lacks suitable evidence or a human-origin disposition.
|
|
69
103
|
*/
|
|
@@ -5,8 +5,18 @@
|
|
|
5
5
|
* plan item needs either typed evidence or a human-origin disposition before complete
|
|
6
6
|
* may advance it. Kind suitability: merge/review alone cannot satisfy smoke, UAT,
|
|
7
7
|
* deploy, or observed_behavior requirements.
|
|
8
|
+
*
|
|
9
|
+
* Canonical item keys are namespaced under #1620 / #3305 (Option B):
|
|
10
|
+
* - plan.items[].x-directive/evidence
|
|
11
|
+
* - plan.items[].x-directive/disposition
|
|
12
|
+
* Bare `evidence` / `disposition` are not valid typed evidence (no dual-read).
|
|
13
|
+
* ITEM_CORE is not expanded with bare keys; verify:vbrief-conformance rejects them.
|
|
8
14
|
*/
|
|
9
15
|
import { isHumanOrigin } from "../authz/origin.js";
|
|
16
|
+
/** Canonical namespaced key for typed acceptance evidence (#3305 / #1620). */
|
|
17
|
+
export const ACCEPTANCE_EVIDENCE_KEY = "x-directive/evidence";
|
|
18
|
+
/** Canonical namespaced key for human-origin disposition (#3305 / #1620). */
|
|
19
|
+
export const ACCEPTANCE_DISPOSITION_KEY = "x-directive/disposition";
|
|
10
20
|
/** Closed evidence kinds (locked Q3). */
|
|
11
21
|
export const ACCEPTANCE_EVIDENCE_KINDS = [
|
|
12
22
|
"test",
|
|
@@ -215,37 +225,100 @@ function itemLabel(item, path) {
|
|
|
215
225
|
}
|
|
216
226
|
return path;
|
|
217
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Read only namespaced acceptance fields (#3305). Bare `evidence` / `disposition`
|
|
230
|
+
* are never treated as success (no permanent dual-read).
|
|
231
|
+
*/
|
|
232
|
+
export function readNamespacedAcceptanceFields(item) {
|
|
233
|
+
const evidence = item[ACCEPTANCE_EVIDENCE_KEY];
|
|
234
|
+
const disposition = item[ACCEPTANCE_DISPOSITION_KEY];
|
|
235
|
+
return {
|
|
236
|
+
evidence,
|
|
237
|
+
disposition,
|
|
238
|
+
hasEvidence: evidence !== undefined && evidence !== null,
|
|
239
|
+
hasDisposition: disposition !== undefined && disposition !== null,
|
|
240
|
+
hasBareEvidence: item.evidence !== undefined && item.evidence !== null,
|
|
241
|
+
hasBareDisposition: item.disposition !== undefined && item.disposition !== null,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/** Clear bare and namespaced acceptance fields so stamps never leave dual/conflicting keys. */
|
|
245
|
+
function clearAcceptanceStampFields(item) {
|
|
246
|
+
delete item.evidence;
|
|
247
|
+
delete item.disposition;
|
|
248
|
+
delete item[ACCEPTANCE_EVIDENCE_KEY];
|
|
249
|
+
delete item[ACCEPTANCE_DISPOSITION_KEY];
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Stamp typed evidence under the canonical namespaced key only.
|
|
253
|
+
* Clears bare evidence/disposition and any prior namespaced disposition so the item
|
|
254
|
+
* cannot carry both acceptance fields after a replace (#3305 Greptile P2).
|
|
255
|
+
*/
|
|
256
|
+
export function stampNamespacedEvidence(item, record) {
|
|
257
|
+
clearAcceptanceStampFields(item);
|
|
258
|
+
item[ACCEPTANCE_EVIDENCE_KEY] = {
|
|
259
|
+
kind: record.kind,
|
|
260
|
+
pointer: record.pointer,
|
|
261
|
+
recorded_at: record.recorded_at,
|
|
262
|
+
recorded_by: record.recorded_by,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Stamp human-origin disposition under the canonical namespaced key only.
|
|
267
|
+
* Clears bare evidence/disposition and any prior namespaced evidence so the item
|
|
268
|
+
* cannot carry both acceptance fields after a replace (#3305 Greptile P2).
|
|
269
|
+
*/
|
|
270
|
+
export function stampNamespacedDisposition(item, record) {
|
|
271
|
+
clearAcceptanceStampFields(item);
|
|
272
|
+
const body = {
|
|
273
|
+
disposition: record.disposition,
|
|
274
|
+
reason: record.reason,
|
|
275
|
+
provenance: { ...record.provenance },
|
|
276
|
+
recorded_at: record.recorded_at,
|
|
277
|
+
};
|
|
278
|
+
if (record.resume_when !== undefined) {
|
|
279
|
+
body.resume_when = record.resume_when;
|
|
280
|
+
}
|
|
281
|
+
item[ACCEPTANCE_DISPOSITION_KEY] = body;
|
|
282
|
+
}
|
|
218
283
|
function evaluateOneItem(item, path) {
|
|
219
284
|
const title = itemLabel(item, path);
|
|
220
285
|
const status = String(item.status ?? "");
|
|
221
286
|
if (!NON_TERMINAL_ITEM_STATUSES.has(status)) {
|
|
287
|
+
// Already-terminal: complete does not re-validate typed evidence (#3240 / #3305).
|
|
288
|
+
// Suitability/provenance apply only when advancing non-terminal items. Pre-marking
|
|
289
|
+
// items completed with narrative-only fields still skips the typed gate — that is
|
|
290
|
+
// intentional for fail/cancel and historical terminals, not a silent dual success path.
|
|
222
291
|
return {
|
|
223
292
|
path,
|
|
224
293
|
title,
|
|
225
294
|
outcome: "already_terminal",
|
|
226
|
-
detail: `status=${status || "(empty)"} (not advanced)`,
|
|
295
|
+
detail: `status=${status || "(empty)"} (not advanced; typed evidence not re-checked)`,
|
|
227
296
|
};
|
|
228
297
|
}
|
|
229
|
-
const
|
|
230
|
-
const
|
|
298
|
+
const fields = readNamespacedAcceptanceFields(item);
|
|
299
|
+
const { hasEvidence, hasDisposition, hasBareEvidence, hasBareDisposition } = fields;
|
|
231
300
|
if (hasEvidence && hasDisposition) {
|
|
232
301
|
return {
|
|
233
302
|
path,
|
|
234
303
|
title,
|
|
235
304
|
outcome: "invalid",
|
|
236
|
-
detail:
|
|
305
|
+
detail: `exactly one of ${ACCEPTANCE_EVIDENCE_KEY} or ${ACCEPTANCE_DISPOSITION_KEY} required; both present`,
|
|
237
306
|
};
|
|
238
307
|
}
|
|
239
308
|
if (!hasEvidence && !hasDisposition) {
|
|
309
|
+
const bareHint = hasBareEvidence || hasBareDisposition
|
|
310
|
+
? ` bare evidence/disposition ignored — use ${ACCEPTANCE_EVIDENCE_KEY} or ${ACCEPTANCE_DISPOSITION_KEY} (#3305);`
|
|
311
|
+
: "";
|
|
240
312
|
return {
|
|
241
313
|
path,
|
|
242
314
|
title,
|
|
243
315
|
outcome: "missing",
|
|
244
|
-
detail:
|
|
316
|
+
detail: `no ${ACCEPTANCE_EVIDENCE_KEY} or ${ACCEPTANCE_DISPOSITION_KEY};` +
|
|
317
|
+
`${bareHint} scope:complete refuses to auto-complete (#3240)`,
|
|
245
318
|
};
|
|
246
319
|
}
|
|
247
320
|
if (hasDisposition) {
|
|
248
|
-
const parsed = parseDisposition(
|
|
321
|
+
const parsed = parseDisposition(fields.disposition);
|
|
249
322
|
if (!parsed.ok) {
|
|
250
323
|
return { path, title, outcome: "invalid", detail: parsed.message };
|
|
251
324
|
}
|
|
@@ -257,7 +330,7 @@ function evaluateOneItem(item, path) {
|
|
|
257
330
|
disposition: parsed.record,
|
|
258
331
|
};
|
|
259
332
|
}
|
|
260
|
-
const parsed = parseEvidence(
|
|
333
|
+
const parsed = parseEvidence(fields.evidence);
|
|
261
334
|
if (!parsed.ok) {
|
|
262
335
|
return { path, title, outcome: "invalid", detail: parsed.message };
|
|
263
336
|
}
|
|
@@ -315,12 +388,13 @@ export function evaluateAcceptanceEvidenceGate(plan) {
|
|
|
315
388
|
const lines = blockers.map((r) => ` - ${r.path} "${r.title}": ${r.detail}`);
|
|
316
389
|
return {
|
|
317
390
|
ok: false,
|
|
318
|
-
message: `Acceptance evidence required for scope:complete (#3240). ` +
|
|
391
|
+
message: `Acceptance evidence required for scope:complete (#3240 / #3305). ` +
|
|
319
392
|
`${blockers.length} criterion/criteria missing suitable evidence or disposition:\n` +
|
|
320
393
|
`${lines.join("\n")}\n` +
|
|
321
|
-
`Each non-terminal plan item needs
|
|
394
|
+
`Each non-terminal plan item needs ${ACCEPTANCE_EVIDENCE_KEY} ` +
|
|
322
395
|
`{kind: test|review|merge|deploy|smoke|uat|observed_behavior, pointer, recorded_at, recorded_by} ` +
|
|
323
|
-
`or
|
|
396
|
+
`or ${ACCEPTANCE_DISPOSITION_KEY} {disposition: waived|deferred|not_applicable, reason, provenance (human-origin), recorded_at}. ` +
|
|
397
|
+
`Bare evidence/disposition keys are not valid (#1620 / #3305). ` +
|
|
324
398
|
`merge/review alone cannot satisfy smoke|uat|deploy|observed_behavior criteria.`,
|
|
325
399
|
reports,
|
|
326
400
|
};
|
|
@@ -34,6 +34,11 @@ export interface ApplyDecompositionOptions {
|
|
|
34
34
|
draftPath: string;
|
|
35
35
|
checkOnly: boolean;
|
|
36
36
|
date: string;
|
|
37
|
+
/**
|
|
38
|
+
* Optional GitHub-style repo (owner/name). When omitted, resolved via
|
|
39
|
+
* DEFT_TRIAGE_REPO / git remote origin so repo-bound structural grants match (#3291).
|
|
40
|
+
*/
|
|
41
|
+
repo?: string | null;
|
|
37
42
|
}
|
|
38
43
|
export declare function applyDecomposition(opts: ApplyDecompositionOptions): string[];
|
|
39
44
|
/** CLI entry for scope-decompose (mirrors scope_decompose.py main()). */
|
package/dist/scope/decompose.js
CHANGED
|
@@ -14,6 +14,7 @@ import { claimSingleUseGrantForApply } from "../authz/store.js";
|
|
|
14
14
|
import { containedWrite } from "../fs/contained-write.js";
|
|
15
15
|
import { ProjectionContainmentError } from "../fs/projection-containment.js";
|
|
16
16
|
import { hasArtifactSuffix, LEGACY_ARTIFACT_DIR, MIGRATED_ARTIFACT_DIR, resolveLifecycleRoot, } from "../layout/resolve.js";
|
|
17
|
+
import { resolveRepo } from "../triage/queue/repo.js";
|
|
17
18
|
import { referenceWithDefaultTrust, slugify } from "../vbrief-build/build.js";
|
|
18
19
|
import { EMITTED_VBRIEF_VERSION } from "../vbrief-build/constants.js";
|
|
19
20
|
import { formatCoverageReportLine, validateCoverageMap } from "./coverage-map.js";
|
|
@@ -828,6 +829,9 @@ function buildChildVbrief(opts) {
|
|
|
828
829
|
}
|
|
829
830
|
export function applyDecomposition(opts) {
|
|
830
831
|
const { projectRoot, parentPath, draftPath, checkOnly, date } = opts;
|
|
832
|
+
// Repo identity for structural apply grants that pin scope.repo (#3291).
|
|
833
|
+
const explicitRepo = (opts.repo ?? "").trim();
|
|
834
|
+
const repo = explicitRepo.length > 0 ? explicitRepo : resolveRepo(null, projectRoot);
|
|
831
835
|
const vbriefDirPath = vbriefDir(projectRoot);
|
|
832
836
|
const parent = loadJson(parentPath);
|
|
833
837
|
// Single draft read: digest must bind the exact bytes used to build child docs (#3239 P1).
|
|
@@ -929,13 +933,15 @@ export function applyDecomposition(opts) {
|
|
|
929
933
|
}
|
|
930
934
|
if (checkOnly)
|
|
931
935
|
return actions;
|
|
932
|
-
// #3239: structural apply requires human-origin grant bound to exact draft digest
|
|
933
|
-
// from the single load above.
|
|
936
|
+
// #3239 / #3291: structural apply requires human-origin grant bound to exact draft digest
|
|
937
|
+
// from the single load above. Thread repo into both evaluator calls so repo-bound grants
|
|
938
|
+
// match. --check is ungated (returned earlier).
|
|
934
939
|
const authz = evaluateDecomposeStructuralApply({
|
|
935
940
|
projectRoot,
|
|
936
941
|
parentPath,
|
|
937
942
|
draftPath,
|
|
938
943
|
draftDigest,
|
|
944
|
+
repo,
|
|
939
945
|
});
|
|
940
946
|
if (!authz.allowed) {
|
|
941
947
|
throw new DecompositionError(authz.reason);
|
|
@@ -1015,12 +1021,15 @@ export function applyDecomposition(opts) {
|
|
|
1015
1021
|
if (authz.humanApprovalRef !== null) {
|
|
1016
1022
|
const claim = claimSingleUseGrantForApply(projectRoot, authz.humanApprovalRef, {
|
|
1017
1023
|
revalidate: (grant) => {
|
|
1024
|
+
// Same repo binding as the initial check (#3291) — under-lock revalidation must not
|
|
1025
|
+
// silently drop project identity or a repo-bound grant would fail closed incorrectly.
|
|
1018
1026
|
const again = evaluateDecomposeStructuralApply({
|
|
1019
1027
|
projectRoot,
|
|
1020
1028
|
parentPath,
|
|
1021
1029
|
draftPath,
|
|
1022
1030
|
draftDigest,
|
|
1023
1031
|
grants: [grant],
|
|
1032
|
+
repo,
|
|
1024
1033
|
});
|
|
1025
1034
|
return again.allowed ? { ok: true } : { ok: false, reason: again.reason };
|
|
1026
1035
|
},
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AC-pass banking checkpoint (#3285).
|
|
3
|
+
*
|
|
4
|
+
* When stated acceptance criteria first pass, FINALIZE: record a durable bank
|
|
5
|
+
* checkpoint, optionally append a bank-event to the run summary, and refuse
|
|
6
|
+
* self-imposed deepening unless remaining budget meets the surplus threshold
|
|
7
|
+
* (default 20% of max turns/cost). Post-bank out-of-scope findings are
|
|
8
|
+
* reported, not chased, when surplus is insufficient.
|
|
9
|
+
*
|
|
10
|
+
* Sharpens #3266 bank-the-pass. Composes product-first done-gate (#3284) and
|
|
11
|
+
* optional DEFT_RUN_SUMMARY_PATH telemetry (#3282 hook, fail-open).
|
|
12
|
+
*/
|
|
13
|
+
import { type AcPassBankingConfig } from "../policy/ac-pass-banking.js";
|
|
14
|
+
import type { HardEffortBudget, VerificationDepthPolicy } from "./effort-budget.js";
|
|
15
|
+
/** Durable bank ledger directory (gitignored under `.deft/`). */
|
|
16
|
+
export declare const AC_PASS_BANK_DIR = ".deft/ac-pass-banks";
|
|
17
|
+
export declare const AC_PASS_BANK_SCHEMA_VERSION: 1;
|
|
18
|
+
/** Env path for optional JSONL run summary (#3282). Unset = silent. */
|
|
19
|
+
export declare const ENV_RUN_SUMMARY_PATH = "DEFT_RUN_SUMMARY_PATH";
|
|
20
|
+
export type PostBankFindingAction = "report" | "chase" | "fix-regression";
|
|
21
|
+
export type AcPassNextAction = "still_open" | "finalize_and_ship" | "finalize_and_deepen";
|
|
22
|
+
export interface SurplusEvaluation {
|
|
23
|
+
readonly hasSurplus: boolean;
|
|
24
|
+
/** Remaining / max when both known; null when unknown. */
|
|
25
|
+
readonly remainingFraction: number | null;
|
|
26
|
+
readonly surplusThreshold: number;
|
|
27
|
+
readonly axis: "turns" | "cost" | "both" | "unknown";
|
|
28
|
+
readonly reason: string;
|
|
29
|
+
}
|
|
30
|
+
export interface PostBankFinding {
|
|
31
|
+
readonly summary: string;
|
|
32
|
+
readonly action: PostBankFindingAction;
|
|
33
|
+
readonly recordedAt: string;
|
|
34
|
+
readonly regressesStatedAc: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface AcPassBankRecord {
|
|
37
|
+
readonly schemaVersion: typeof AC_PASS_BANK_SCHEMA_VERSION;
|
|
38
|
+
readonly scopeId: string;
|
|
39
|
+
readonly bankedAt: string;
|
|
40
|
+
readonly headSha: string | null;
|
|
41
|
+
readonly remainingTurns: number | null;
|
|
42
|
+
readonly remainingBudget: number | null;
|
|
43
|
+
readonly maxTurns: number | null;
|
|
44
|
+
readonly maxBudget: number | null;
|
|
45
|
+
readonly surplusThreshold: number;
|
|
46
|
+
readonly hadSurplus: boolean;
|
|
47
|
+
readonly nextAction: Exclude<AcPassNextAction, "still_open">;
|
|
48
|
+
readonly postBankFindings: readonly PostBankFinding[];
|
|
49
|
+
}
|
|
50
|
+
export interface EvaluateSurplusInput {
|
|
51
|
+
readonly budget: HardEffortBudget;
|
|
52
|
+
/** Fraction 0–1; default from policy / {@link DEFAULT_SURPLUS_THRESHOLD}. */
|
|
53
|
+
readonly surplusThreshold?: number;
|
|
54
|
+
}
|
|
55
|
+
export interface EvaluateAcPassBankingInput {
|
|
56
|
+
readonly budget: HardEffortBudget;
|
|
57
|
+
/** Whether stated AC (verify:ac / official checker) is met. */
|
|
58
|
+
readonly statedAcceptanceMet: boolean;
|
|
59
|
+
readonly config?: Partial<AcPassBankingConfig>;
|
|
60
|
+
/** Absolute turn reserve floor (still applied; #3266). Default 3. */
|
|
61
|
+
readonly deepenReserveTurns?: number;
|
|
62
|
+
readonly deepenReserveBudget?: number | null;
|
|
63
|
+
}
|
|
64
|
+
export interface AcPassBankingDecision {
|
|
65
|
+
readonly nextAction: AcPassNextAction;
|
|
66
|
+
readonly surplus: SurplusEvaluation;
|
|
67
|
+
readonly depthPolicy: VerificationDepthPolicy;
|
|
68
|
+
readonly deepeningAllowed: boolean;
|
|
69
|
+
readonly notes: readonly string[];
|
|
70
|
+
}
|
|
71
|
+
export interface BankAcPassInput {
|
|
72
|
+
readonly projectRoot: string;
|
|
73
|
+
readonly scopeId: string;
|
|
74
|
+
readonly budget: HardEffortBudget;
|
|
75
|
+
readonly surplus: SurplusEvaluation;
|
|
76
|
+
readonly nextAction: Exclude<AcPassNextAction, "still_open">;
|
|
77
|
+
readonly headSha?: string | null;
|
|
78
|
+
readonly now?: string;
|
|
79
|
+
readonly environ?: Readonly<Record<string, string | undefined>>;
|
|
80
|
+
}
|
|
81
|
+
export interface DecidePostBankFindingInput {
|
|
82
|
+
readonly findingSummary: string;
|
|
83
|
+
readonly regressesStatedAc: boolean;
|
|
84
|
+
readonly hasSurplus: boolean;
|
|
85
|
+
readonly now?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Evaluate whether remaining budget meets the surplus threshold (#3285).
|
|
89
|
+
*
|
|
90
|
+
* When max is known: remaining/max >= threshold on every known axis.
|
|
91
|
+
* When only remaining is known (no max): surplus is false (fail-safe) —
|
|
92
|
+
* absolute #3266 reserve still applies separately via recommendVerificationDepth.
|
|
93
|
+
*/
|
|
94
|
+
export declare function evaluateSurplus(input: EvaluateSurplusInput): SurplusEvaluation;
|
|
95
|
+
/**
|
|
96
|
+
* Full AC-pass banking decision: still open / finalize+ship / finalize+deepen.
|
|
97
|
+
*/
|
|
98
|
+
export declare function evaluateAcPassBanking(input: EvaluateAcPassBankingInput): AcPassBankingDecision;
|
|
99
|
+
/**
|
|
100
|
+
* Post-bank finding disposition: report (default) vs chase (only with surplus)
|
|
101
|
+
* vs fix-regression (always when stated AC regressed).
|
|
102
|
+
*/
|
|
103
|
+
export declare function decidePostBankFinding(input: DecidePostBankFindingInput): PostBankFinding;
|
|
104
|
+
export declare function acPassBanksDir(projectRoot: string): string;
|
|
105
|
+
/**
|
|
106
|
+
* Sanitize scopeId for a ledger filename without unbounded quantifiers (CodeQL).
|
|
107
|
+
* Walks characters once — O(n), no ReDoS risk on pathological "-" runs.
|
|
108
|
+
*/
|
|
109
|
+
export declare function sanitizeScopeIdForFilename(scopeId: string): string;
|
|
110
|
+
/** Stable filename for a scope bank record. */
|
|
111
|
+
export declare function acPassBankFilename(scopeId: string): string;
|
|
112
|
+
export declare function acPassBankPath(projectRoot: string, scopeId: string): string;
|
|
113
|
+
/**
|
|
114
|
+
* Persist a bank checkpoint that survives session death (#3285).
|
|
115
|
+
* Also appends a bank-event to DEFT_RUN_SUMMARY_PATH when set (fail-open).
|
|
116
|
+
*/
|
|
117
|
+
/** Append-only findings journal (never truncated by re-bank). */
|
|
118
|
+
export declare function acPassFindingsJournalPath(projectRoot: string, scopeId: string): string;
|
|
119
|
+
export declare function bankAcPass(input: BankAcPassInput): AcPassBankRecord;
|
|
120
|
+
/** Recover complete JSON objects from a (possibly truncated) array body. */
|
|
121
|
+
export declare function recoverCompleteJsonObjects(arrayBody: string): readonly unknown[];
|
|
122
|
+
export declare function recoverFindingsFromLedgerText(raw: string): readonly PostBankFinding[];
|
|
123
|
+
/**
|
|
124
|
+
* Load bank record. When both primary and .tmp exist, prefer a fully-valid
|
|
125
|
+
* JSON primary over a partial tmp, and union recovered findings so partial
|
|
126
|
+
* recovery cannot erase durable history (#3285 Greptile residual).
|
|
127
|
+
*/
|
|
128
|
+
export declare function readAcPassBank(projectRoot: string, scopeId: string): AcPassBankRecord | null;
|
|
129
|
+
/**
|
|
130
|
+
* Append a post-bank finding to an existing bank record (report/chase/fix).
|
|
131
|
+
*/
|
|
132
|
+
export declare function recordPostBankFinding(projectRoot: string, scopeId: string, finding: PostBankFinding): AcPassBankRecord | null;
|
|
133
|
+
export interface BankEventPayload {
|
|
134
|
+
readonly type: "ac_pass_bank" | "ac_pass_post_bank_finding" | "ac_pass_deepening_skipped";
|
|
135
|
+
readonly schemaVersion: number;
|
|
136
|
+
readonly scopeId?: string;
|
|
137
|
+
readonly bankedAt?: string;
|
|
138
|
+
readonly nextAction?: string;
|
|
139
|
+
readonly hadSurplus?: boolean;
|
|
140
|
+
readonly surplusThreshold?: number;
|
|
141
|
+
readonly remainingFraction?: number | null;
|
|
142
|
+
readonly remainingTurns?: number | null;
|
|
143
|
+
readonly remainingBudget?: number | null;
|
|
144
|
+
readonly maxTurns?: number | null;
|
|
145
|
+
readonly maxBudget?: number | null;
|
|
146
|
+
readonly headSha?: string | null;
|
|
147
|
+
readonly path?: string;
|
|
148
|
+
readonly finding?: PostBankFinding;
|
|
149
|
+
readonly note?: string;
|
|
150
|
+
readonly [key: string]: unknown;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Format one JSONL bank-event line for run-summary telemetry (#3285 / #3282).
|
|
154
|
+
*/
|
|
155
|
+
export declare function formatBankEventLine(event: BankEventPayload): string;
|
|
156
|
+
/**
|
|
157
|
+
* Append bank event to DEFT_RUN_SUMMARY_PATH when set.
|
|
158
|
+
* Unset = silent. `-` = stdout. Failures warn once to stderr (fail-open).
|
|
159
|
+
*/
|
|
160
|
+
export declare function appendBankEventToRunSummary(input: {
|
|
161
|
+
readonly environ?: Readonly<Record<string, string | undefined>>;
|
|
162
|
+
readonly event: BankEventPayload;
|
|
163
|
+
readonly writeLine?: (path: string, line: string) => void;
|
|
164
|
+
readonly warn?: (message: string) => void;
|
|
165
|
+
}): {
|
|
166
|
+
written: boolean;
|
|
167
|
+
path: string | null;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Simulated run used by the surplus-insufficient acceptance test (#3285):
|
|
171
|
+
* AC passes → bank → extra checks would exceed budget → ship + report finding.
|
|
172
|
+
*/
|
|
173
|
+
export declare function simulateSurplusInsufficientRun(input: {
|
|
174
|
+
readonly projectRoot: string;
|
|
175
|
+
readonly scopeId: string;
|
|
176
|
+
readonly budget: HardEffortBudget;
|
|
177
|
+
readonly findingSummary: string;
|
|
178
|
+
readonly surplusThreshold?: number;
|
|
179
|
+
readonly headSha?: string | null;
|
|
180
|
+
readonly now?: string;
|
|
181
|
+
readonly environ?: Readonly<Record<string, string | undefined>>;
|
|
182
|
+
}): {
|
|
183
|
+
readonly decision: AcPassBankingDecision;
|
|
184
|
+
readonly bank: AcPassBankRecord;
|
|
185
|
+
readonly finding: PostBankFinding;
|
|
186
|
+
readonly shipped: boolean;
|
|
187
|
+
readonly findingAction: PostBankFindingAction;
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Resolve policy config for a project root (typed → env → default).
|
|
191
|
+
*/
|
|
192
|
+
export declare function resolveBankingConfigForRoot(projectRoot?: string | null, environ?: Readonly<Record<string, string | undefined>>): AcPassBankingConfig;
|
|
193
|
+
export interface MaybeBankOnAcPassInput {
|
|
194
|
+
readonly projectRoot: string;
|
|
195
|
+
/** plan.id or path-derived scope key. */
|
|
196
|
+
readonly scopeId: string;
|
|
197
|
+
readonly budget?: HardEffortBudget;
|
|
198
|
+
readonly config?: Partial<AcPassBankingConfig>;
|
|
199
|
+
readonly headSha?: string | null;
|
|
200
|
+
readonly now?: string;
|
|
201
|
+
readonly environ?: Readonly<Record<string, string | undefined>>;
|
|
202
|
+
/**
|
|
203
|
+
* Only bank when real acceptance commands executed and passed.
|
|
204
|
+
* Soft/advisory passes with zero runs do not bank.
|
|
205
|
+
*/
|
|
206
|
+
readonly executableRuns: number;
|
|
207
|
+
readonly quiet?: boolean;
|
|
208
|
+
}
|
|
209
|
+
export interface MaybeBankOnAcPassResult {
|
|
210
|
+
readonly banked: boolean;
|
|
211
|
+
readonly decision: AcPassBankingDecision | null;
|
|
212
|
+
readonly bank: AcPassBankRecord | null;
|
|
213
|
+
readonly notes: readonly string[];
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Production bridge (#3285 Greptile P1): after verify:ac reports executable
|
|
217
|
+
* success, FINALIZE the bank checkpoint + surplus decision.
|
|
218
|
+
* Throws on I/O failure so verify:ac can fail closed (checkpoint mandatory).
|
|
219
|
+
*/
|
|
220
|
+
export declare function maybeBankOnAcPass(input: MaybeBankOnAcPassInput): MaybeBankOnAcPassResult;
|
|
221
|
+
//# sourceMappingURL=ac-pass-banking.d.ts.map
|