@deftai/directive-core 0.104.0 → 0.106.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 +1108 -67
- package/dist/check/cached-orchestrator.d.ts +1 -1
- package/dist/check/cached-orchestrator.js +2 -2
- package/dist/check/named-cause.d.ts +1 -1
- package/dist/check/named-cause.js +34 -4
- package/dist/codebase/default-extractor.d.ts +5 -0
- package/dist/codebase/default-extractor.js +7 -15
- package/dist/deposit/copy-tree.js +60 -0
- package/dist/deposit/python-free.js +26 -18
- package/dist/doctor/checks.d.ts +8 -0
- package/dist/doctor/checks.js +37 -25
- package/dist/doctor/doctor-state.d.ts +4 -0
- package/dist/doctor/doctor-state.js +7 -1
- package/dist/doctor/main.js +9 -19
- package/dist/doctor/types.d.ts +9 -0
- package/dist/forward-coverage/diff-coverage.d.ts +39 -0
- package/dist/forward-coverage/diff-coverage.js +112 -0
- package/dist/forward-coverage/diff-lines.d.ts +19 -0
- package/dist/forward-coverage/diff-lines.js +173 -0
- package/dist/forward-coverage/evaluate.d.ts +24 -9
- package/dist/forward-coverage/evaluate.js +125 -19
- package/dist/fs/contained-write.d.ts +115 -1
- package/dist/fs/contained-write.js +241 -5
- package/dist/fs/mutation-ledger.d.ts +54 -0
- package/dist/fs/mutation-ledger.js +133 -0
- package/dist/fs/non-product-dirs.d.ts +79 -0
- package/dist/fs/non-product-dirs.js +96 -0
- package/dist/hooks/dispatcher.d.ts +3 -1
- package/dist/hooks/dispatcher.js +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +18 -16
- package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
- package/dist/init-deposit/core-guard-pin-content.js +393 -0
- package/dist/init-deposit/gitignore.js +9 -0
- package/dist/init-deposit/hygiene.d.ts +47 -11
- package/dist/init-deposit/hygiene.js +172 -37
- package/dist/init-deposit/legacy-detect.js +6 -2
- package/dist/init-deposit/refresh.d.ts +21 -1
- package/dist/init-deposit/refresh.js +106 -9
- package/dist/init-deposit/scaffold.js +28 -279
- package/dist/init-deposit/slash-deposit.js +13 -7
- package/dist/init-deposit/xbrief-projections.d.ts +8 -1
- package/dist/init-deposit/xbrief-projections.js +24 -11
- package/dist/intake/clause-derivation.d.ts +47 -1
- package/dist/intake/clause-derivation.js +238 -9
- package/dist/intake/issue-ingest.d.ts +3 -1
- package/dist/intake/issue-ingest.js +35 -6
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
- package/dist/lifecycle-visible/evaluate.d.ts +98 -0
- package/dist/lifecycle-visible/evaluate.js +710 -0
- package/dist/lifecycle-visible/index.d.ts +2 -0
- package/dist/lifecycle-visible/index.js +2 -0
- package/dist/literal-acceptance/capture.d.ts +10 -0
- package/dist/literal-acceptance/capture.js +226 -77
- package/dist/literal-acceptance/evaluate.d.ts +29 -4
- package/dist/literal-acceptance/evaluate.js +70 -2
- package/dist/literal-acceptance/index.d.ts +3 -3
- package/dist/literal-acceptance/index.js +3 -3
- package/dist/literal-acceptance/safety.d.ts +41 -0
- package/dist/literal-acceptance/safety.js +126 -2
- package/dist/literal-acceptance/types.d.ts +8 -0
- package/dist/orchestration/judgment-policy.d.ts +13 -0
- package/dist/orchestration/judgment-policy.js +15 -0
- package/dist/orchestration/probe-session.js +13 -8
- package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
- package/dist/orchestration/verify-judgment-gates.js +43 -11
- package/dist/orphan-active/evaluate.d.ts +7 -1
- package/dist/orphan-active/evaluate.js +102 -23
- package/dist/platform/platform-capabilities.js +2 -3
- package/dist/policy/base-branch.d.ts +37 -0
- package/dist/policy/base-branch.js +114 -0
- package/dist/policy/branch-sync.d.ts +80 -0
- package/dist/policy/branch-sync.js +211 -0
- package/dist/policy/ceremony-dial-escalation.js +1 -0
- package/dist/policy/ceremony-dial.js +11 -21
- package/dist/policy/delivery-branch.d.ts +5 -3
- package/dist/policy/delivery-branch.js +7 -3
- package/dist/policy/file-size-thresholds.d.ts +24 -0
- package/dist/policy/file-size-thresholds.js +23 -0
- package/dist/policy/forge-outage-retry.d.ts +47 -0
- package/dist/policy/forge-outage-retry.js +157 -0
- package/dist/policy/host-hooks.d.ts +20 -0
- package/dist/policy/host-hooks.js +121 -2
- package/dist/policy/index.d.ts +7 -0
- package/dist/policy/index.js +66 -7
- package/dist/policy/org-force-on-migration.js +2 -1
- package/dist/policy/plan-extensions.d.ts +1 -1
- package/dist/policy/plan-extensions.js +2 -0
- package/dist/policy/product-signal.js +6 -7
- package/dist/policy/project-invariants.d.ts +50 -0
- package/dist/policy/project-invariants.js +205 -0
- package/dist/policy/require-human-merge.js +8 -6
- package/dist/policy/resolve.d.ts +7 -2
- package/dist/policy/resolve.js +25 -8
- package/dist/policy/sync-default.d.ts +129 -0
- package/dist/policy/sync-default.js +452 -0
- package/dist/policy/sync-max-files.d.ts +93 -0
- package/dist/policy/sync-max-files.js +192 -0
- package/dist/policy/value-feedback.js +7 -8
- package/dist/pr-monitor/absent-required.d.ts +11 -0
- package/dist/pr-monitor/absent-required.js +61 -0
- package/dist/pr-monitor/constants.d.ts +7 -0
- package/dist/pr-monitor/constants.js +7 -0
- package/dist/pr-monitor/index.d.ts +2 -1
- package/dist/pr-monitor/index.js +2 -1
- package/dist/pr-monitor/main.js +4 -0
- package/dist/pr-monitor/monitor.js +24 -1
- package/dist/pr-wait-mergeable/classify.js +6 -0
- package/dist/preflight/evaluate.d.ts +4 -0
- package/dist/preflight/evaluate.js +35 -1
- package/dist/preflight/index.d.ts +4 -0
- package/dist/preflight/index.js +2 -0
- package/dist/preflight/intended-placement.d.ts +62 -0
- package/dist/preflight/intended-placement.js +275 -0
- package/dist/preflight/project-invariants-gate.d.ts +29 -0
- package/dist/preflight/project-invariants-gate.js +82 -0
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +15 -1
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
- package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
- package/dist/product-first-done-gate/acceptance.d.ts +7 -4
- package/dist/product-first-done-gate/acceptance.js +79 -8
- package/dist/product-first-done-gate/empty-resolution.d.ts +4 -1
- package/dist/product-first-done-gate/empty-resolution.js +12 -1
- package/dist/product-first-done-gate/evaluate.d.ts +16 -0
- package/dist/product-first-done-gate/evaluate.js +298 -34
- package/dist/product-first-done-gate/index.d.ts +2 -0
- package/dist/product-first-done-gate/index.js +1 -0
- package/dist/release/build-dist.d.ts +101 -0
- package/dist/release/build-dist.js +428 -46
- package/dist/release/closed-verb-gate.d.ts +12 -0
- package/dist/release/closed-verb-gate.js +51 -0
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.js +1 -0
- package/dist/release/pipeline.js +7 -0
- package/dist/release/types.d.ts +12 -0
- package/dist/render/constants.d.ts +2 -1
- package/dist/render/constants.js +2 -1
- package/dist/render/framework-commands.js +4 -0
- package/dist/render/spec-validate.js +23 -12
- package/dist/run-summary/emit.d.ts +16 -10
- package/dist/run-summary/emit.js +26 -15
- package/dist/run-summary/index.d.ts +3 -2
- package/dist/run-summary/index.js +2 -1
- package/dist/run-summary/session-id.d.ts +21 -0
- package/dist/run-summary/session-id.js +92 -0
- package/dist/run-summary/types.d.ts +33 -4
- package/dist/run-summary/types.js +1 -0
- package/dist/scope/acceptance-evidence.d.ts +19 -7
- package/dist/scope/acceptance-evidence.js +38 -11
- package/dist/scope/delivery-evidence.d.ts +3 -3
- package/dist/scope/delivery-evidence.js +22 -27
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/main.js +15 -5
- package/dist/scope/parent-lineage.js +7 -6
- package/dist/scope/project-invariant-coverage.d.ts +54 -0
- package/dist/scope/project-invariant-coverage.js +322 -0
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope/transition.js +1 -1
- package/dist/scope-provenance/compare-intent.d.ts +27 -0
- package/dist/scope-provenance/compare-intent.js +233 -0
- package/dist/scope-provenance/digest.d.ts +18 -1
- package/dist/scope-provenance/digest.js +16 -11
- package/dist/scope-provenance/evaluate.d.ts +5 -1
- package/dist/scope-provenance/evaluate.js +67 -7
- package/dist/scope-provenance/extract-intent.d.ts +43 -0
- package/dist/scope-provenance/extract-intent.js +262 -0
- package/dist/scope-provenance/index.d.ts +7 -1
- package/dist/scope-provenance/index.js +7 -1
- package/dist/scope-provenance/intent-digest.d.ts +12 -0
- package/dist/scope-provenance/intent-digest.js +33 -0
- package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
- package/dist/scope-provenance/intent-evaluate.js +149 -0
- package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
- package/dist/scope-provenance/json-tokenizer.js +225 -0
- package/dist/scope-provenance/known-machine.d.ts +38 -0
- package/dist/scope-provenance/known-machine.js +157 -0
- package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
- package/dist/scope-provenance/mint-artifacts.js +425 -0
- package/dist/session/ac-pass-banking.d.ts +9 -36
- package/dist/session/ac-pass-banking.js +33 -79
- package/dist/session/ac-pass-reuse.d.ts +53 -0
- package/dist/session/ac-pass-reuse.js +95 -0
- package/dist/session/git.js +19 -4
- package/dist/session/index.d.ts +4 -0
- package/dist/session/index.js +4 -0
- package/dist/session/occupancy-stress-worker.d.ts +7 -0
- package/dist/session/occupancy-stress-worker.js +36 -0
- package/dist/session/occupancy.d.ts +97 -0
- package/dist/session/occupancy.js +422 -0
- package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
- package/dist/session/process-cost.d.ts +32 -10
- package/dist/session/process-cost.js +189 -1
- package/dist/session/product-state-hash.d.ts +26 -0
- package/dist/session/product-state-hash.js +700 -0
- package/dist/session/ritual-entrypoint.js +16 -1
- package/dist/session/session-ready.d.ts +2 -0
- package/dist/session/session-ready.js +52 -30
- package/dist/session/session-start.d.ts +13 -0
- package/dist/session/session-start.js +103 -9
- package/dist/session/verify-ac-session-cache.d.ts +42 -0
- package/dist/session/verify-ac-session-cache.js +126 -0
- package/dist/session/verify-session-ritual.d.ts +28 -0
- package/dist/session/verify-session-ritual.js +97 -5
- package/dist/slash/openclaw-deposit.js +13 -9
- package/dist/slice/constants.d.ts +2 -2
- package/dist/slice/constants.js +2 -2
- package/dist/slice/existing.js +9 -3
- package/dist/slice/lock.d.ts +16 -1
- package/dist/slice/lock.js +137 -11
- package/dist/story-ready/evaluate.d.ts +2 -0
- package/dist/story-ready/evaluate.js +13 -0
- package/dist/swarm/complete-cohort.d.ts +3 -0
- package/dist/swarm/complete-cohort.js +59 -11
- package/dist/swarm/finalize-cohort-cli.d.ts +7 -2
- package/dist/swarm/finalize-cohort-cli.js +165 -35
- package/dist/swarm/finalize-cohort.d.ts +1 -0
- package/dist/swarm/finalize-cohort.js +47 -4
- package/dist/swarm/launch.d.ts +22 -0
- package/dist/swarm/launch.js +155 -0
- package/dist/swarm/routing-set-cli.d.ts +11 -1
- package/dist/swarm/routing-set-cli.js +15 -3
- package/dist/swarm/routing-verify.d.ts +13 -1
- package/dist/swarm/routing-verify.js +60 -21
- package/dist/swarm/routing.d.ts +14 -0
- package/dist/swarm/routing.js +53 -3
- package/dist/telemetry-coverage/fake-trial.js +10 -0
- package/dist/telemetry-coverage/kinds.js +2 -0
- package/dist/triage/actions/index.js +4 -1
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/help/registry-data.d.ts +1 -1
- package/dist/triage/help/registry-data.js +1 -1
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/ts-check-lane/index.d.ts +3 -0
- package/dist/ts-check-lane/index.js +2 -0
- package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
- package/dist/ts-check-lane/progress-reporter.js +38 -0
- package/dist/ts-check-lane/progress.d.ts +32 -0
- package/dist/ts-check-lane/progress.js +57 -0
- package/dist/ts-check-lane/run-lane.d.ts +3 -1
- package/dist/ts-check-lane/run-lane.js +8 -6
- package/dist/validate-content/validate-links.d.ts +8 -0
- package/dist/validate-content/validate-links.js +9 -15
- package/dist/value/feedback-file.js +12 -2
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-build/index.d.ts +1 -0
- package/dist/vbrief-build/index.js +1 -0
- package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
- package/dist/vbrief-build/project-invariants-io.js +41 -0
- package/dist/vbrief-reconcile/graph.js +18 -1
- package/dist/vbrief-reconcile/index.d.ts +1 -1
- package/dist/vbrief-reconcile/index.js +1 -1
- package/dist/vbrief-reconcile/types.d.ts +13 -0
- package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
- package/dist/vbrief-reconcile/umbrellas.js +261 -26
- package/dist/vbrief-validate/index.d.ts +1 -1
- package/dist/vbrief-validate/index.js +1 -1
- package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
- package/dist/vbrief-validate/plan-hooks.js +68 -0
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/verify-ac/evaluate.d.ts +7 -1
- package/dist/verify-ac/evaluate.js +34 -26
- package/dist/verify-ac/flag.d.ts +4 -0
- package/dist/verify-ac/flag.js +16 -0
- package/dist/verify-ac/index.d.ts +2 -2
- package/dist/verify-ac/index.js +2 -2
- package/dist/verify-env/agent-hook-readiness.d.ts +2 -2
- package/dist/verify-env/agent-hook-readiness.js +12 -8
- package/dist/verify-env/agent-hooks-live-probe.d.ts +5 -1
- package/dist/verify-env/agent-hooks-live-probe.js +26 -5
- package/dist/verify-env/agent-hooks.js +3 -4
- package/dist/verify-source/contained-writes.js +2 -0
- package/dist/verify-source/verify-stubs.d.ts +15 -1
- package/dist/verify-source/verify-stubs.js +20 -16
- package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
- package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
- package/dist/xbrief-migrate/migrate-project.js +2 -5
- package/package.json +7 -3
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One mint writes record + preimage + both digests (#3376 R7 / #3385).
|
|
3
|
+
* Dest publish is two-phase under a per-plan lock: both dests land as
|
|
4
|
+
* `.next` first, then dests are copied from that pair. A crash leaves
|
|
5
|
+
* `.next` and/or a bak journal; recover finishes the flip or restores
|
|
6
|
+
* the prior pair (or neither dest) without waiting for a remint.
|
|
7
|
+
* Caught write failures still restore or clear dests.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
10
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
11
|
+
import { ContainedWriteError, ContainedWriteErrorCode, containedRemove, containedWrite, } from "../fs/contained-write.js";
|
|
12
|
+
import { approvedScopeDir, approvedScopeIntentPath, approvedScopeRecordPath, buildApprovedScopeRecord, } from "./digest.js";
|
|
13
|
+
import { extractIntentFromRaw, } from "./extract-intent.js";
|
|
14
|
+
import { computeIntentDigest, INTENT_DIGEST_ALGO } from "./intent-digest.js";
|
|
15
|
+
export { approvedScopeIntentPath, approvedScopeRecordPath };
|
|
16
|
+
export class MintPairRollbackError extends Error {
|
|
17
|
+
writeError;
|
|
18
|
+
restoreError;
|
|
19
|
+
clearError;
|
|
20
|
+
constructor(writeError, restoreError, clearError) {
|
|
21
|
+
const writeMsg = errorMessage(writeError);
|
|
22
|
+
const restoreMsg = errorMessage(restoreError);
|
|
23
|
+
const clearSuffix = clearError === undefined
|
|
24
|
+
? "; leftover dests were cleared"
|
|
25
|
+
: `; leftover dests could not be cleared (${errorMessage(clearError)})`;
|
|
26
|
+
super(`Mint dest publish failed (${writeMsg}); rollback also failed (${restoreMsg})${clearSuffix}. Do not commit a partial approved-scope pair.`);
|
|
27
|
+
this.name = "MintPairRollbackError";
|
|
28
|
+
this.writeError = writeError;
|
|
29
|
+
this.restoreError = restoreError;
|
|
30
|
+
this.clearError = clearError;
|
|
31
|
+
this.cause = writeError;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function errorMessage(err) {
|
|
35
|
+
return err instanceof Error ? err.message : String(err);
|
|
36
|
+
}
|
|
37
|
+
function snapshotText(path) {
|
|
38
|
+
if (!existsSync(path))
|
|
39
|
+
return null;
|
|
40
|
+
return readFileSync(path, "utf8");
|
|
41
|
+
}
|
|
42
|
+
function restoreText(root, path, snapshot) {
|
|
43
|
+
rmSync(path, { force: true, recursive: true });
|
|
44
|
+
if (snapshot === null)
|
|
45
|
+
return;
|
|
46
|
+
containedWrite({
|
|
47
|
+
root,
|
|
48
|
+
target: path,
|
|
49
|
+
data: snapshot,
|
|
50
|
+
mode: "replace",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function writeTempPayload(root, target, data) {
|
|
54
|
+
containedWrite({
|
|
55
|
+
root,
|
|
56
|
+
target,
|
|
57
|
+
data,
|
|
58
|
+
mode: "create",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function restoreDestDefault(input) {
|
|
62
|
+
restoreText(input.root, input.target, input.snapshot);
|
|
63
|
+
}
|
|
64
|
+
function removeDestDefault(input) {
|
|
65
|
+
rmSync(input.target, { force: true });
|
|
66
|
+
}
|
|
67
|
+
function pairStem(recordPath) {
|
|
68
|
+
return basename(recordPath).replace(/\.json$/i, "");
|
|
69
|
+
}
|
|
70
|
+
export function approvedScopePairLockPath(dir, recordPath) {
|
|
71
|
+
return join(dir, `.${pairStem(recordPath)}.pair.lock.tmp`);
|
|
72
|
+
}
|
|
73
|
+
export function approvedScopePairJournalPaths(dir, intentPath, recordPath) {
|
|
74
|
+
return {
|
|
75
|
+
publishing: join(dir, `.${pairStem(recordPath)}.publishing.bak`),
|
|
76
|
+
intentBak: join(dir, `${basename(intentPath)}.bak`),
|
|
77
|
+
recordBak: join(dir, `${basename(recordPath)}.bak`),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function approvedScopePairNextPaths(dir, intentPath, recordPath) {
|
|
81
|
+
return {
|
|
82
|
+
intentNext: join(dir, `${basename(intentPath)}.next.tmp`),
|
|
83
|
+
recordNext: join(dir, `${basename(recordPath)}.next.tmp`),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function publishFromNext(root, next, dest) {
|
|
87
|
+
if (!existsSync(next)) {
|
|
88
|
+
throw new Error(`mint pair next payload missing: ${basename(next)}`);
|
|
89
|
+
}
|
|
90
|
+
containedWrite({
|
|
91
|
+
root,
|
|
92
|
+
target: dest,
|
|
93
|
+
data: readFileSync(next, "utf8"),
|
|
94
|
+
mode: "replace",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function writeBak(root, src, bak) {
|
|
98
|
+
if (!existsSync(src)) {
|
|
99
|
+
rmSync(bak, { force: true });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
containedWrite({
|
|
103
|
+
root,
|
|
104
|
+
target: bak,
|
|
105
|
+
data: readFileSync(src, "utf8"),
|
|
106
|
+
mode: "replace",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function clearJournal(paths) {
|
|
110
|
+
rmSync(paths.publishing, { force: true });
|
|
111
|
+
rmSync(paths.intentBak, { force: true });
|
|
112
|
+
rmSync(paths.recordBak, { force: true });
|
|
113
|
+
}
|
|
114
|
+
function pairStemFromPublishingName(name) {
|
|
115
|
+
const match = name.match(/^\.(.+)\.publishing\.bak$/i);
|
|
116
|
+
return match?.[1] ?? null;
|
|
117
|
+
}
|
|
118
|
+
function pairStemFromNextName(name) {
|
|
119
|
+
if (!name.endsWith(".next.tmp"))
|
|
120
|
+
return null;
|
|
121
|
+
const base = name.slice(0, -".next.tmp".length);
|
|
122
|
+
if (base.endsWith(".intent.json"))
|
|
123
|
+
return base.slice(0, -".intent.json".length);
|
|
124
|
+
if (base.endsWith(".json"))
|
|
125
|
+
return base.slice(0, -".json".length);
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Finish a staged dest flip from `.next`, or restore the bak pair / clear dests.
|
|
130
|
+
* Does not wait for a remint.
|
|
131
|
+
*/
|
|
132
|
+
export function recoverIncompleteApprovedScopePair(input) {
|
|
133
|
+
const root = resolve(input.projectRoot);
|
|
134
|
+
const dir = approvedScopeDir(input.projectRoot);
|
|
135
|
+
const journal = approvedScopePairJournalPaths(dir, input.intentPath, input.recordPath);
|
|
136
|
+
const next = approvedScopePairNextPaths(dir, input.intentPath, input.recordPath);
|
|
137
|
+
const intentNext = snapshotText(next.intentNext);
|
|
138
|
+
const recordNext = snapshotText(next.recordNext);
|
|
139
|
+
if (intentNext !== null && recordNext !== null) {
|
|
140
|
+
restoreText(root, input.intentPath, intentNext);
|
|
141
|
+
restoreText(root, input.recordPath, recordNext);
|
|
142
|
+
rmSync(next.intentNext, { force: true });
|
|
143
|
+
rmSync(next.recordNext, { force: true });
|
|
144
|
+
clearJournal(journal);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
if (!existsSync(journal.publishing)) {
|
|
148
|
+
const leftover = intentNext !== null || recordNext !== null;
|
|
149
|
+
rmSync(next.intentNext, { force: true });
|
|
150
|
+
rmSync(next.recordNext, { force: true });
|
|
151
|
+
return leftover;
|
|
152
|
+
}
|
|
153
|
+
const intentBak = snapshotText(journal.intentBak);
|
|
154
|
+
const recordBak = snapshotText(journal.recordBak);
|
|
155
|
+
if (intentBak !== null || recordBak !== null) {
|
|
156
|
+
restoreText(root, input.intentPath, intentBak);
|
|
157
|
+
restoreText(root, input.recordPath, recordBak);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
rmSync(input.intentPath, { force: true });
|
|
161
|
+
rmSync(input.recordPath, { force: true });
|
|
162
|
+
}
|
|
163
|
+
rmSync(next.intentNext, { force: true });
|
|
164
|
+
rmSync(next.recordNext, { force: true });
|
|
165
|
+
clearJournal(journal);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
/** Recover every incomplete pair under `.deft/approved-scope/`. */
|
|
169
|
+
export function recoverApprovedScopePairs(projectRoot) {
|
|
170
|
+
const dir = approvedScopeDir(projectRoot);
|
|
171
|
+
if (!existsSync(dir))
|
|
172
|
+
return 0;
|
|
173
|
+
const stems = new Set();
|
|
174
|
+
for (const name of readdirSync(dir)) {
|
|
175
|
+
const fromPub = pairStemFromPublishingName(name);
|
|
176
|
+
if (fromPub !== null)
|
|
177
|
+
stems.add(fromPub);
|
|
178
|
+
const fromNext = pairStemFromNextName(name);
|
|
179
|
+
if (fromNext !== null)
|
|
180
|
+
stems.add(fromNext);
|
|
181
|
+
}
|
|
182
|
+
let recovered = 0;
|
|
183
|
+
for (const stem of stems) {
|
|
184
|
+
const did = recoverIncompleteApprovedScopePair({
|
|
185
|
+
projectRoot,
|
|
186
|
+
intentPath: join(dir, `${stem}.intent.json`),
|
|
187
|
+
recordPath: join(dir, `${stem}.json`),
|
|
188
|
+
});
|
|
189
|
+
if (did)
|
|
190
|
+
recovered += 1;
|
|
191
|
+
}
|
|
192
|
+
return recovered;
|
|
193
|
+
}
|
|
194
|
+
function ownerPidAlive(lockPath) {
|
|
195
|
+
try {
|
|
196
|
+
const owner = Number(readFileSync(lockPath, "utf8").trim());
|
|
197
|
+
if (!Number.isInteger(owner) || owner <= 0)
|
|
198
|
+
return true;
|
|
199
|
+
process.kill(owner, 0);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const code = err.code;
|
|
204
|
+
return code !== "ESRCH";
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function reclaimDeadPairLock(lockPath) {
|
|
208
|
+
const stale = `${lockPath}.stale`;
|
|
209
|
+
try {
|
|
210
|
+
renameSync(lockPath, stale);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
rmSync(stale, { force: true });
|
|
216
|
+
}
|
|
217
|
+
function isCreateExistsError(err) {
|
|
218
|
+
return err instanceof ContainedWriteError && err.code === ContainedWriteErrorCode.EXISTS;
|
|
219
|
+
}
|
|
220
|
+
function withPairLock(root, lockPath, waitMs, fn) {
|
|
221
|
+
mkdirSync(dirname(lockPath), { recursive: true });
|
|
222
|
+
const deadline = Date.now() + waitMs;
|
|
223
|
+
let held = false;
|
|
224
|
+
while (!held) {
|
|
225
|
+
try {
|
|
226
|
+
containedWrite({
|
|
227
|
+
root,
|
|
228
|
+
target: lockPath,
|
|
229
|
+
data: `${process.pid}\n`,
|
|
230
|
+
mode: "create",
|
|
231
|
+
mutation: false,
|
|
232
|
+
});
|
|
233
|
+
held = true;
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
if (!isCreateExistsError(err))
|
|
237
|
+
throw err;
|
|
238
|
+
if (!ownerPidAlive(lockPath)) {
|
|
239
|
+
reclaimDeadPairLock(lockPath);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (Date.now() > deadline) {
|
|
243
|
+
throw new Error(`timed out acquiring mint pair lock for ${basename(lockPath)}`);
|
|
244
|
+
}
|
|
245
|
+
const spinEnd = Date.now() + 20;
|
|
246
|
+
while (Date.now() < spinEnd) {
|
|
247
|
+
/* spin */
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
return fn();
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
try {
|
|
256
|
+
containedRemove({ root, target: lockPath, mutation: false });
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
rmSync(lockPath, { force: true });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function restorePair(restore, dests) {
|
|
264
|
+
const failures = [];
|
|
265
|
+
for (const dest of dests) {
|
|
266
|
+
try {
|
|
267
|
+
restore(dest);
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
failures.push(`${basename(dest.target)}: ${errorMessage(err)}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (failures.length > 0) {
|
|
274
|
+
throw new Error(failures.join("; "));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function clearDestPair(input) {
|
|
278
|
+
const dests = [
|
|
279
|
+
{ root: input.root, target: input.intentPath, snapshot: input.prevIntent },
|
|
280
|
+
{ root: input.root, target: input.recordPath, snapshot: input.prevRecord },
|
|
281
|
+
];
|
|
282
|
+
const removed = [];
|
|
283
|
+
const failures = [];
|
|
284
|
+
for (const dest of dests) {
|
|
285
|
+
try {
|
|
286
|
+
input.remove({ root: dest.root, target: dest.target });
|
|
287
|
+
removed.push(dest);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
failures.push(`${basename(dest.target)}: ${errorMessage(err)}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (failures.length === 0)
|
|
294
|
+
return;
|
|
295
|
+
const putBackFailures = [];
|
|
296
|
+
for (const dest of removed) {
|
|
297
|
+
try {
|
|
298
|
+
restoreDestDefault(dest);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
putBackFailures.push(`${basename(dest.target)}: ${errorMessage(err)}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const putBackSuffix = putBackFailures.length > 0
|
|
305
|
+
? `; removed dests could not be put back (${putBackFailures.join("; ")})`
|
|
306
|
+
: "";
|
|
307
|
+
throw new Error(`${failures.join("; ")}${putBackSuffix}`);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Write record + preimage as one fail-closed pair.
|
|
311
|
+
* Phase 1 writes both dests to `.next`. Phase 2 copies dests from that pair.
|
|
312
|
+
* Recover finishes the flip or restores the bak pair without a remint.
|
|
313
|
+
*/
|
|
314
|
+
export function writeApprovedScopePair(input) {
|
|
315
|
+
const root = resolve(input.projectRoot);
|
|
316
|
+
const dir = approvedScopeDir(input.projectRoot);
|
|
317
|
+
mkdirSync(dir, { recursive: true });
|
|
318
|
+
const lockPath = approvedScopePairLockPath(dir, input.recordPath);
|
|
319
|
+
const journal = approvedScopePairJournalPaths(dir, input.intentPath, input.recordPath);
|
|
320
|
+
const restore = input.restoreDest ?? restoreDestDefault;
|
|
321
|
+
const remove = input.removeDest ?? removeDestDefault;
|
|
322
|
+
const customPublish = input.publishDest;
|
|
323
|
+
const next = approvedScopePairNextPaths(dir, input.intentPath, input.recordPath);
|
|
324
|
+
withPairLock(root, lockPath, input.lockWaitMs ?? 30_000, () => {
|
|
325
|
+
recoverIncompleteApprovedScopePair({
|
|
326
|
+
projectRoot: input.projectRoot,
|
|
327
|
+
intentPath: input.intentPath,
|
|
328
|
+
recordPath: input.recordPath,
|
|
329
|
+
});
|
|
330
|
+
const prevIntent = snapshotText(input.intentPath);
|
|
331
|
+
const prevRecord = snapshotText(input.recordPath);
|
|
332
|
+
const dests = [
|
|
333
|
+
{ root, target: input.intentPath, snapshot: prevIntent },
|
|
334
|
+
{ root, target: input.recordPath, snapshot: prevRecord },
|
|
335
|
+
];
|
|
336
|
+
let destPublished = false;
|
|
337
|
+
try {
|
|
338
|
+
writeTempPayload(root, next.intentNext, input.intentData);
|
|
339
|
+
writeTempPayload(root, next.recordNext, input.recordData);
|
|
340
|
+
writeBak(root, input.intentPath, journal.intentBak);
|
|
341
|
+
writeBak(root, input.recordPath, journal.recordBak);
|
|
342
|
+
containedWrite({
|
|
343
|
+
root,
|
|
344
|
+
target: journal.publishing,
|
|
345
|
+
data: "publishing\n",
|
|
346
|
+
mode: "replace",
|
|
347
|
+
});
|
|
348
|
+
destPublished = true;
|
|
349
|
+
if (customPublish) {
|
|
350
|
+
customPublish({ root, target: input.intentPath, data: input.intentData });
|
|
351
|
+
customPublish({ root, target: input.recordPath, data: input.recordData });
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
publishFromNext(root, next.intentNext, input.intentPath);
|
|
355
|
+
publishFromNext(root, next.recordNext, input.recordPath);
|
|
356
|
+
}
|
|
357
|
+
clearJournal(journal);
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
if (destPublished) {
|
|
361
|
+
try {
|
|
362
|
+
restorePair(restore, dests);
|
|
363
|
+
clearJournal(journal);
|
|
364
|
+
}
|
|
365
|
+
catch (restoreErr) {
|
|
366
|
+
try {
|
|
367
|
+
clearDestPair({
|
|
368
|
+
root,
|
|
369
|
+
intentPath: input.intentPath,
|
|
370
|
+
recordPath: input.recordPath,
|
|
371
|
+
prevIntent,
|
|
372
|
+
prevRecord,
|
|
373
|
+
remove,
|
|
374
|
+
});
|
|
375
|
+
clearJournal(journal);
|
|
376
|
+
}
|
|
377
|
+
catch (clearErr) {
|
|
378
|
+
throw new MintPairRollbackError(err, restoreErr, clearErr);
|
|
379
|
+
}
|
|
380
|
+
throw new MintPairRollbackError(err, restoreErr);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
throw err;
|
|
384
|
+
}
|
|
385
|
+
finally {
|
|
386
|
+
rmSync(next.intentNext, { force: true });
|
|
387
|
+
rmSync(next.recordNext, { force: true });
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
export function mintApprovedScopeArtifacts(input) {
|
|
392
|
+
const extracted = extractIntentFromRaw(input.rawText, {
|
|
393
|
+
projectRoot: input.projectRoot,
|
|
394
|
+
...input.extract,
|
|
395
|
+
});
|
|
396
|
+
if (!extracted.ok) {
|
|
397
|
+
throw new Error(extracted.error);
|
|
398
|
+
}
|
|
399
|
+
const intentDigest = computeIntentDigest(extracted.preimage);
|
|
400
|
+
const record = {
|
|
401
|
+
...buildApprovedScopeRecord({
|
|
402
|
+
xbriefRelPath: input.xbriefRelPath,
|
|
403
|
+
payload: input.payload,
|
|
404
|
+
approvedAt: input.approvedAt,
|
|
405
|
+
humanApproval: input.humanApproval,
|
|
406
|
+
}),
|
|
407
|
+
intentDigest,
|
|
408
|
+
digestAlgo: INTENT_DIGEST_ALGO,
|
|
409
|
+
};
|
|
410
|
+
const intentPath = approvedScopeIntentPath(input.projectRoot, record.planId);
|
|
411
|
+
const recordPath = approvedScopeRecordPath(input.projectRoot, record.planId);
|
|
412
|
+
writeApprovedScopePair({
|
|
413
|
+
projectRoot: input.projectRoot,
|
|
414
|
+
intentPath,
|
|
415
|
+
recordPath,
|
|
416
|
+
intentData: `${JSON.stringify(extracted.preimage, null, 2)}\n`,
|
|
417
|
+
recordData: `${JSON.stringify(record, null, 2)}\n`,
|
|
418
|
+
publishDest: input.publishDest,
|
|
419
|
+
restoreDest: input.restoreDest,
|
|
420
|
+
removeDest: input.removeDest,
|
|
421
|
+
lockWaitMs: input.lockWaitMs,
|
|
422
|
+
});
|
|
423
|
+
return { record, preimage: extracted.preimage, recordPath, intentPath };
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=mint-artifacts.js.map
|
|
@@ -38,6 +38,8 @@ export interface AcPassBankRecord {
|
|
|
38
38
|
readonly scopeId: string;
|
|
39
39
|
readonly bankedAt: string;
|
|
40
40
|
readonly headSha: string | null;
|
|
41
|
+
/** Product+acceptance digest; missing/empty is stale for #3387 reuse. */
|
|
42
|
+
readonly productStateHash?: string | null;
|
|
41
43
|
readonly remainingTurns: number | null;
|
|
42
44
|
readonly remainingBudget: number | null;
|
|
43
45
|
readonly maxTurns: number | null;
|
|
@@ -75,6 +77,7 @@ export interface BankAcPassInput {
|
|
|
75
77
|
readonly surplus: SurplusEvaluation;
|
|
76
78
|
readonly nextAction: Exclude<AcPassNextAction, "still_open">;
|
|
77
79
|
readonly headSha?: string | null;
|
|
80
|
+
readonly productStateHash?: string | null;
|
|
78
81
|
readonly now?: string;
|
|
79
82
|
readonly environ?: Readonly<Record<string, string | undefined>>;
|
|
80
83
|
}
|
|
@@ -130,42 +133,6 @@ export declare function readAcPassBank(projectRoot: string, scopeId: string): Ac
|
|
|
130
133
|
* Append a post-bank finding to an existing bank record (report/chase/fix).
|
|
131
134
|
*/
|
|
132
135
|
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
136
|
/**
|
|
170
137
|
* Simulated run used by the surplus-insufficient acceptance test (#3285):
|
|
171
138
|
* AC passes → bank → extra checks would exceed budget → ship + report finding.
|
|
@@ -205,6 +172,12 @@ export interface MaybeBankOnAcPassInput {
|
|
|
205
172
|
*/
|
|
206
173
|
readonly executableRuns: number;
|
|
207
174
|
readonly quiet?: boolean;
|
|
175
|
+
readonly productStateHash?: string | null;
|
|
176
|
+
/**
|
|
177
|
+
* Bank a verified-pass walk even when no shell runs were recorded (#3558).
|
|
178
|
+
* Soft/advisory empty passes still skip via executableRuns === 0.
|
|
179
|
+
*/
|
|
180
|
+
readonly verifiedPass?: boolean;
|
|
208
181
|
}
|
|
209
182
|
export interface MaybeBankOnAcPassResult {
|
|
210
183
|
readonly banked: boolean;
|
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { createHash } from "node:crypto";
|
|
14
14
|
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync } from "node:fs";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { join, resolve } from "node:path";
|
|
16
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
17
17
|
import { DEFAULT_SURPLUS_THRESHOLD, resolveAcPassBanking, } from "../policy/ac-pass-banking.js";
|
|
18
|
+
import { RunSummaryEmitter } from "../run-summary/emit.js";
|
|
18
19
|
import { detectHardEffortBudget, formatDeepeningSkippedNote, recommendVerificationDepth, } from "./effort-budget.js";
|
|
20
|
+
import { gitHead } from "./git.js";
|
|
19
21
|
/** Durable bank ledger directory (gitignored under `.deft/`). */
|
|
20
22
|
export const AC_PASS_BANK_DIR = ".deft/ac-pass-banks";
|
|
21
23
|
export const AC_PASS_BANK_SCHEMA_VERSION = 1;
|
|
@@ -320,6 +322,7 @@ export function bankAcPass(input) {
|
|
|
320
322
|
scopeId: input.scopeId,
|
|
321
323
|
bankedAt,
|
|
322
324
|
headSha: input.headSha ?? null,
|
|
325
|
+
productStateHash: input.productStateHash ?? prior?.productStateHash ?? null,
|
|
323
326
|
remainingTurns: input.budget.remainingTurns,
|
|
324
327
|
remainingBudget: input.budget.remainingBudget,
|
|
325
328
|
maxTurns: input.budget.maxTurns,
|
|
@@ -358,25 +361,31 @@ export function bankAcPass(input) {
|
|
|
358
361
|
durablePath = tmpPath;
|
|
359
362
|
}
|
|
360
363
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
364
|
+
try {
|
|
365
|
+
const env = { ...(input.environ ?? process.env) };
|
|
366
|
+
const emitter = new RunSummaryEmitter({
|
|
367
|
+
projectRoot: root,
|
|
368
|
+
env,
|
|
369
|
+
component: "ac-pass-banking",
|
|
370
|
+
});
|
|
371
|
+
emitter.emitAcPassBank({
|
|
372
|
+
scope_id: record.scopeId,
|
|
373
|
+
banked_at: record.bankedAt,
|
|
374
|
+
next_action: record.nextAction,
|
|
375
|
+
had_surplus: record.hadSurplus,
|
|
376
|
+
surplus_threshold: record.surplusThreshold,
|
|
377
|
+
remaining_fraction: input.surplus.remainingFraction,
|
|
378
|
+
remaining_turns: record.remainingTurns,
|
|
379
|
+
remaining_budget: record.remainingBudget,
|
|
380
|
+
max_turns: record.maxTurns,
|
|
381
|
+
max_budget: record.maxBudget,
|
|
382
|
+
head_sha: record.headSha,
|
|
377
383
|
path: durablePath,
|
|
378
|
-
}
|
|
379
|
-
}
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
// fail-open
|
|
388
|
+
}
|
|
380
389
|
return record;
|
|
381
390
|
}
|
|
382
391
|
/**
|
|
@@ -487,6 +496,7 @@ function recoveredStubRecord(scopeId, findings) {
|
|
|
487
496
|
// valid primary ledger (#3285 Greptile residual).
|
|
488
497
|
bankedAt: "1970-01-01T00:00:00Z",
|
|
489
498
|
headSha: null,
|
|
499
|
+
productStateHash: null,
|
|
490
500
|
remainingTurns: null,
|
|
491
501
|
remainingBudget: null,
|
|
492
502
|
maxTurns: null,
|
|
@@ -616,63 +626,6 @@ export function recordPostBankFinding(projectRoot, scopeId, finding) {
|
|
|
616
626
|
}
|
|
617
627
|
return updated;
|
|
618
628
|
}
|
|
619
|
-
/**
|
|
620
|
-
* Format one JSONL bank-event line for run-summary telemetry (#3285 / #3282).
|
|
621
|
-
*/
|
|
622
|
-
export function formatBankEventLine(event) {
|
|
623
|
-
return JSON.stringify({
|
|
624
|
-
...event,
|
|
625
|
-
ts: typeof event.bankedAt === "string" ? event.bankedAt : utcIso(),
|
|
626
|
-
source: "ac-pass-banking",
|
|
627
|
-
issue: 3285,
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Append bank event to DEFT_RUN_SUMMARY_PATH when set.
|
|
632
|
-
* Unset = silent. `-` = stdout. Failures warn once to stderr (fail-open).
|
|
633
|
-
*/
|
|
634
|
-
export function appendBankEventToRunSummary(input) {
|
|
635
|
-
const environ = input.environ ?? process.env;
|
|
636
|
-
const raw = (environ[ENV_RUN_SUMMARY_PATH] ?? "").trim();
|
|
637
|
-
if (!raw) {
|
|
638
|
-
return { written: false, path: null };
|
|
639
|
-
}
|
|
640
|
-
const line = `${formatBankEventLine(input.event)}\n`;
|
|
641
|
-
if (raw === "-") {
|
|
642
|
-
process.stdout.write(line);
|
|
643
|
-
return { written: true, path: "-" };
|
|
644
|
-
}
|
|
645
|
-
try {
|
|
646
|
-
if (input.writeLine) {
|
|
647
|
-
input.writeLine(raw, line);
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
const abs = resolve(raw);
|
|
651
|
-
const parent = dirname(abs);
|
|
652
|
-
if (!existsSync(parent)) {
|
|
653
|
-
mkdirSync(parent, { recursive: true });
|
|
654
|
-
}
|
|
655
|
-
// Contain under the parent directory of the summary file.
|
|
656
|
-
containedWrite({
|
|
657
|
-
root: parent,
|
|
658
|
-
target: abs,
|
|
659
|
-
data: line,
|
|
660
|
-
mode: "append",
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
return { written: true, path: raw };
|
|
664
|
-
}
|
|
665
|
-
catch (err) {
|
|
666
|
-
const msg = err instanceof ContainedWriteError
|
|
667
|
-
? err.message
|
|
668
|
-
: err instanceof Error
|
|
669
|
-
? err.message
|
|
670
|
-
: String(err);
|
|
671
|
-
const warn = input.warn ?? ((m) => process.stderr.write(`${m}\n`));
|
|
672
|
-
warn(`[deft ac-pass-banking] run-summary write failed path=${raw}: ${msg} (#3285)`);
|
|
673
|
-
return { written: false, path: raw };
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
629
|
/**
|
|
677
630
|
* Simulated run used by the surplus-insufficient acceptance test (#3285):
|
|
678
631
|
* AC passes → bank → extra checks would exceed budget → ship + report finding.
|
|
@@ -730,7 +683,7 @@ export function resolveBankingConfigForRoot(projectRoot, environ) {
|
|
|
730
683
|
* Throws on I/O failure so verify:ac can fail closed (checkpoint mandatory).
|
|
731
684
|
*/
|
|
732
685
|
export function maybeBankOnAcPass(input) {
|
|
733
|
-
if (input.executableRuns <= 0) {
|
|
686
|
+
if (input.executableRuns <= 0 && input.verifiedPass !== true) {
|
|
734
687
|
return { banked: false, decision: null, bank: null, notes: [] };
|
|
735
688
|
}
|
|
736
689
|
const budget = input.budget ?? detectHardEffortBudget({ environ: input.environ ?? process.env });
|
|
@@ -747,7 +700,8 @@ export function maybeBankOnAcPass(input) {
|
|
|
747
700
|
budget,
|
|
748
701
|
surplus: decision.surplus,
|
|
749
702
|
nextAction,
|
|
750
|
-
headSha: input.headSha
|
|
703
|
+
headSha: input.headSha !== undefined ? input.headSha : gitHead(input.projectRoot).head,
|
|
704
|
+
productStateHash: input.productStateHash ?? null,
|
|
751
705
|
now: input.now,
|
|
752
706
|
environ: input.environ,
|
|
753
707
|
});
|