@deftai/directive-core 0.101.0 → 0.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authz/classify.js +97 -8
- package/dist/check/cached-orchestrator.d.ts +4 -0
- package/dist/check/cached-orchestrator.js +70 -5
- package/dist/check/cli-native-gates.d.ts +43 -0
- package/dist/check/cli-native-gates.js +84 -0
- package/dist/check/index.d.ts +1 -0
- package/dist/check/index.js +1 -0
- package/dist/check/named-cause.js +10 -0
- package/dist/doctor/checks.d.ts +5 -6
- package/dist/doctor/checks.js +13 -56
- package/dist/eval/later-graduation.d.ts +39 -0
- package/dist/eval/later-graduation.js +91 -0
- package/dist/eval/report.d.ts +6 -0
- package/dist/eval/report.js +27 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/intake/issue-ingest.js +42 -0
- package/dist/policy/ceremony-dial-escalation.d.ts +52 -0
- package/dist/policy/ceremony-dial-escalation.js +92 -0
- package/dist/policy/ceremony-dial.d.ts +3 -1
- package/dist/policy/ceremony-dial.js +52 -1
- package/dist/policy/check-resume.d.ts +9 -38
- package/dist/policy/check-resume.js +18 -156
- package/dist/policy/coverage-debt.d.ts +18 -37
- package/dist/policy/coverage-debt.js +38 -147
- package/dist/policy/index.d.ts +1 -1
- package/dist/policy/index.js +1 -1
- package/dist/product-first-done-gate/acceptance.js +22 -0
- package/dist/product-first-done-gate/empty-resolution.d.ts +26 -0
- package/dist/product-first-done-gate/empty-resolution.js +38 -0
- package/dist/product-first-done-gate/evaluate.d.ts +28 -2
- package/dist/product-first-done-gate/evaluate.js +209 -53
- package/dist/product-first-done-gate/index.d.ts +1 -0
- package/dist/product-first-done-gate/index.js +1 -0
- package/dist/product-first-done-gate/types.d.ts +3 -0
- package/dist/product-first-done-gate/types.js +0 -7
- package/dist/run-summary/emit.d.ts +11 -1
- package/dist/run-summary/emit.js +48 -2
- package/dist/run-summary/index.d.ts +2 -1
- package/dist/run-summary/index.js +2 -1
- package/dist/run-summary/path.d.ts +1 -1
- package/dist/run-summary/path.js +1 -1
- package/dist/run-summary/share.d.ts +25 -0
- package/dist/run-summary/share.js +106 -0
- package/dist/run-summary/types.d.ts +60 -2
- package/dist/run-summary/types.js +7 -0
- package/dist/scope/acceptance-activate-gate.d.ts +23 -0
- package/dist/scope/acceptance-activate-gate.js +70 -0
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/transition.js +5 -0
- package/dist/session/index.d.ts +0 -1
- package/dist/session/index.js +0 -1
- package/dist/session/orientation-compression.js +19 -9
- package/dist/session/session-start.d.ts +6 -0
- package/dist/session/session-start.js +44 -22
- package/dist/session/toolchain-preflight.d.ts +15 -0
- package/dist/session/toolchain-preflight.js +65 -5
- package/dist/verify-ac/clauses.d.ts +51 -0
- package/dist/verify-ac/clauses.js +490 -0
- package/dist/verify-ac/evaluate.d.ts +55 -0
- package/dist/verify-ac/evaluate.js +145 -0
- package/dist/verify-ac/flag.d.ts +35 -0
- package/dist/verify-ac/flag.js +104 -0
- package/dist/verify-ac/index.d.ts +10 -0
- package/dist/verify-ac/index.js +10 -0
- package/package.json +7 -3
- package/dist/policy/coverage-check-resume-presets.d.ts +0 -46
- package/dist/policy/coverage-check-resume-presets.js +0 -228
- package/dist/session/coverage-check-resume-nudge.d.ts +0 -34
- package/dist/session/coverage-check-resume-nudge.js +0 -66
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #3286 Later graduation trigger from a #3282 run summary (#3320).
|
|
3
|
+
*
|
|
4
|
+
* Named surface: eval:report prints graduate / do-not-graduate / unevaluable.
|
|
5
|
+
* A graduation or decline MUST cite an emitted share. Counts without a
|
|
6
|
+
* denominator are unevaluable — never invent a ratio.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { isAbsolute, resolve } from "node:path";
|
|
10
|
+
import { computeRitualGateShare, parseRunSummaryJsonl, } from "../run-summary/share.js";
|
|
11
|
+
import { DEFAULT_RUN_SUMMARY_BASENAME, ENV_RUN_SUMMARY_PATH } from "../run-summary/types.js";
|
|
12
|
+
/** #3286 Later trigger: graduate when ritual+gate share is at least this fraction. */
|
|
13
|
+
export const LATER_GRADUATION_SHARE_THRESHOLD = 0.25;
|
|
14
|
+
function formatPercent(value) {
|
|
15
|
+
return `${(value * 100).toFixed(1)}%`;
|
|
16
|
+
}
|
|
17
|
+
export function laterGraduationFromShare(share, threshold = LATER_GRADUATION_SHARE_THRESHOLD) {
|
|
18
|
+
if (!share.evaluable || share.share === null || share.totalToolTurns === null) {
|
|
19
|
+
return {
|
|
20
|
+
evaluable: false,
|
|
21
|
+
verdict: "unevaluable",
|
|
22
|
+
summary: "trigger unevaluable (no tool/turn denominator on run summary)",
|
|
23
|
+
ritualGateCount: share.ritualGateCount,
|
|
24
|
+
totalToolTurns: share.totalToolTurns,
|
|
25
|
+
share: null,
|
|
26
|
+
threshold,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const graduate = share.share >= threshold;
|
|
30
|
+
const verdict = graduate ? "graduate" : "do-not-graduate";
|
|
31
|
+
return {
|
|
32
|
+
evaluable: true,
|
|
33
|
+
verdict,
|
|
34
|
+
summary: `ritual+gate share ${formatPercent(share.share)} (${share.ritualGateCount}/${share.totalToolTurns}) — ${verdict} (threshold ${formatPercent(threshold)})`,
|
|
35
|
+
ritualGateCount: share.ritualGateCount,
|
|
36
|
+
totalToolTurns: share.totalToolTurns,
|
|
37
|
+
share: share.share,
|
|
38
|
+
threshold,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a readable run-summary path. Unset env + missing default file → null
|
|
43
|
+
* (fail-open / unevaluable). stdout dest (`-`) is not a file.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveRunSummaryReadPath(projectRoot, options = {}) {
|
|
46
|
+
if (options.runSummaryPath !== undefined && options.runSummaryPath.trim().length > 0) {
|
|
47
|
+
return resolve(options.runSummaryPath.trim());
|
|
48
|
+
}
|
|
49
|
+
const env = options.env ?? process.env;
|
|
50
|
+
const raw = env[ENV_RUN_SUMMARY_PATH];
|
|
51
|
+
if (raw !== undefined && raw.trim() === "-") {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (raw !== undefined && raw.trim().length > 0) {
|
|
55
|
+
const trimmed = raw.trim();
|
|
56
|
+
return isAbsolute(trimmed) ? resolve(trimmed) : resolve(projectRoot, trimmed);
|
|
57
|
+
}
|
|
58
|
+
const fallback = resolve(projectRoot, DEFAULT_RUN_SUMMARY_BASENAME);
|
|
59
|
+
return existsSync(fallback) ? fallback : null;
|
|
60
|
+
}
|
|
61
|
+
function readSummaryText(path) {
|
|
62
|
+
try {
|
|
63
|
+
if (!existsSync(path)) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return readFileSync(path, "utf8");
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Evaluate #3286 Later from the run-summary file (or unevaluable). */
|
|
73
|
+
export function evaluateLaterGraduationTrigger(options) {
|
|
74
|
+
const threshold = options.threshold ?? LATER_GRADUATION_SHARE_THRESHOLD;
|
|
75
|
+
const path = resolveRunSummaryReadPath(options.projectRoot, {
|
|
76
|
+
runSummaryPath: options.runSummaryPath,
|
|
77
|
+
env: options.env,
|
|
78
|
+
});
|
|
79
|
+
if (path === null) {
|
|
80
|
+
return laterGraduationFromShare({ evaluable: false, ritualGateCount: 0, totalToolTurns: null, share: null }, threshold);
|
|
81
|
+
}
|
|
82
|
+
const text = readSummaryText(path);
|
|
83
|
+
if (text === null) {
|
|
84
|
+
return laterGraduationFromShare({ evaluable: false, ritualGateCount: 0, totalToolTurns: null, share: null }, threshold);
|
|
85
|
+
}
|
|
86
|
+
return laterGraduationFromShare(computeRitualGateShare(parseRunSummaryJsonl(text)), threshold);
|
|
87
|
+
}
|
|
88
|
+
export function formatLaterGraduationLine(trigger) {
|
|
89
|
+
return `#3286 Later: ${trigger.summary}`;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=later-graduation.js.map
|
package/dist/eval/report.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LaterGraduationTrigger } from "./later-graduation.js";
|
|
1
2
|
import { type GoldenRunRecord } from "./run.js";
|
|
2
3
|
import { type CellVersionPurity, type MixedVersionPolicy } from "./version-pin.js";
|
|
3
4
|
export declare const REPORT_SCHEMA_VERSION: 1;
|
|
@@ -39,6 +40,8 @@ export interface GoldenEvalReport {
|
|
|
39
40
|
readonly holdoutTripwire: HoldoutTripwire;
|
|
40
41
|
/** Cell-level framework version purity for the reported model (#3215). */
|
|
41
42
|
readonly versionPurity: VersionPurityEvidence;
|
|
43
|
+
/** #3286 Later graduation trigger from the run-summary denominator (#3320). */
|
|
44
|
+
readonly laterGraduation: LaterGraduationTrigger;
|
|
42
45
|
}
|
|
43
46
|
export interface ReportGoldenEvalOptions {
|
|
44
47
|
readonly projectRoot?: string;
|
|
@@ -50,6 +53,9 @@ export interface ReportGoldenEvalOptions {
|
|
|
50
53
|
* ledger runs for this model disagree on framework version within a treatment.
|
|
51
54
|
*/
|
|
52
55
|
readonly mixedVersionPolicy?: MixedVersionPolicy;
|
|
56
|
+
/** Override run-summary JSONL path (#3320). Default: DEFT_RUN_SUMMARY_PATH or repo default. */
|
|
57
|
+
readonly runSummaryPath?: string;
|
|
58
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
53
59
|
}
|
|
54
60
|
export interface ReportGoldenEvalResult {
|
|
55
61
|
readonly code: 0 | 1 | 2;
|
package/dist/eval/report.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { resolveEvalPath } from "../layout/resolve.js";
|
|
3
|
+
import { evaluateLaterGraduationTrigger, formatLaterGraduationLine, } from "./later-graduation.js";
|
|
3
4
|
import { GOLDEN_RUNS_HISTORY_REL } from "./run.js";
|
|
4
5
|
import { aggregateCellWithVersionPurity, evaluateLedgerVersionPurity, } from "./version-pin.js";
|
|
5
6
|
export const REPORT_SCHEMA_VERSION = 1;
|
|
@@ -107,17 +108,33 @@ export function goldenRunToVersionedRun(record) {
|
|
|
107
108
|
}
|
|
108
109
|
/** Diff two directive versions with metric deltas and significance (#1703 Tier 2). */
|
|
109
110
|
export function reportGoldenEval(options) {
|
|
110
|
-
|
|
111
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
112
|
+
const laterGraduation = evaluateLaterGraduationTrigger({
|
|
113
|
+
projectRoot,
|
|
114
|
+
runSummaryPath: options.runSummaryPath,
|
|
115
|
+
env: options.env,
|
|
116
|
+
});
|
|
117
|
+
const laterLine = formatLaterGraduationLine(laterGraduation);
|
|
118
|
+
const championMissing = !options.championVersion.trim();
|
|
119
|
+
const challengerMissing = !options.challengerVersion.trim();
|
|
120
|
+
const modelMissing = !options.model.trim();
|
|
121
|
+
if (championMissing && challengerMissing && modelMissing) {
|
|
122
|
+
return {
|
|
123
|
+
code: 0,
|
|
124
|
+
report: null,
|
|
125
|
+
message: `eval:report ${laterLine}`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (championMissing || challengerMissing) {
|
|
111
129
|
return {
|
|
112
130
|
code: 2,
|
|
113
131
|
report: null,
|
|
114
|
-
message:
|
|
132
|
+
message: `eval:report: --champion and --challenger are required\n ${laterLine}`,
|
|
115
133
|
};
|
|
116
134
|
}
|
|
117
|
-
if (
|
|
118
|
-
return { code: 2, report: null, message:
|
|
135
|
+
if (modelMissing) {
|
|
136
|
+
return { code: 2, report: null, message: `eval:report: --model is required\n ${laterLine}` };
|
|
119
137
|
}
|
|
120
|
-
const projectRoot = options.projectRoot ?? process.cwd();
|
|
121
138
|
const policy = options.mixedVersionPolicy ?? "refuse";
|
|
122
139
|
const records = readGoldenRuns(projectRoot);
|
|
123
140
|
const modelRecords = records.filter((r) => r.model === options.model);
|
|
@@ -157,7 +174,7 @@ export function reportGoldenEval(options) {
|
|
|
157
174
|
return {
|
|
158
175
|
code: 1,
|
|
159
176
|
report: null,
|
|
160
|
-
message: `eval:report: mixed framework versions in treatment cell(s) — aggregation refused (#3215)\n ${versionPurity.summary}`,
|
|
177
|
+
message: `eval:report: mixed framework versions in treatment cell(s) — aggregation refused (#3215)\n ${versionPurity.summary}\n ${laterLine}`,
|
|
161
178
|
};
|
|
162
179
|
}
|
|
163
180
|
const champion = findLatestGoldenRun(records, options.championVersion, options.model);
|
|
@@ -166,14 +183,14 @@ export function reportGoldenEval(options) {
|
|
|
166
183
|
return {
|
|
167
184
|
code: 1,
|
|
168
185
|
report: null,
|
|
169
|
-
message: `eval:report: no golden run found for champion v${options.championVersion} model=${options.model}`,
|
|
186
|
+
message: `eval:report: no golden run found for champion v${options.championVersion} model=${options.model}\n ${laterLine}`,
|
|
170
187
|
};
|
|
171
188
|
}
|
|
172
189
|
if (challenger === null) {
|
|
173
190
|
return {
|
|
174
191
|
code: 1,
|
|
175
192
|
report: null,
|
|
176
|
-
message: `eval:report: no golden run found for challenger v${options.challengerVersion} model=${options.model}`,
|
|
193
|
+
message: `eval:report: no golden run found for challenger v${options.challengerVersion} model=${options.model}\n ${laterLine}`,
|
|
177
194
|
};
|
|
178
195
|
}
|
|
179
196
|
const championPrimary = champion.results.filter((r) => !r.holdout);
|
|
@@ -208,6 +225,7 @@ export function reportGoldenEval(options) {
|
|
|
208
225
|
deltas,
|
|
209
226
|
holdoutTripwire,
|
|
210
227
|
versionPurity,
|
|
228
|
+
laterGraduation,
|
|
211
229
|
};
|
|
212
230
|
const lines = [
|
|
213
231
|
`eval:report champion=v${options.championVersion} challenger=v${options.challengerVersion} model=${options.model}`,
|
|
@@ -223,6 +241,7 @@ export function reportGoldenEval(options) {
|
|
|
223
241
|
` version purity: ${versionPurity.pure ? "ok" : "mixed"} — ${versionPurity.summary}`,
|
|
224
242
|
` champion cell pin: v${champion.frameworkVersionPin?.frameworkVersion ?? champion.directiveVersion}`,
|
|
225
243
|
` challenger cell pin: v${challenger.frameworkVersionPin?.frameworkVersion ?? challenger.directiveVersion}`,
|
|
244
|
+
` ${laterLine}`,
|
|
226
245
|
];
|
|
227
246
|
const code = holdoutTripwire.triggered ? 1 : 0;
|
|
228
247
|
return { code, report, message: lines.join("\n") };
|
package/dist/index.d.ts
CHANGED
|
@@ -74,6 +74,7 @@ export * as vbriefBuild from "./vbrief-build/index.js";
|
|
|
74
74
|
export * as vbriefReconcile from "./vbrief-reconcile/index.js";
|
|
75
75
|
export * as vbriefValidate from "./vbrief-validate/index.js";
|
|
76
76
|
export * as vbriefValidation from "./vbrief-validation/index.js";
|
|
77
|
+
export * as verifyAc from "./verify-ac/index.js";
|
|
77
78
|
export * as verifyEnv from "./verify-env/index.js";
|
|
78
79
|
export * as verifySource from "./verify-source/index.js";
|
|
79
80
|
export * as wipCap from "./wip-cap/index.js";
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,7 @@ export * as vbriefBuild from "./vbrief-build/index.js";
|
|
|
75
75
|
export * as vbriefReconcile from "./vbrief-reconcile/index.js";
|
|
76
76
|
export * as vbriefValidate from "./vbrief-validate/index.js";
|
|
77
77
|
export * as vbriefValidation from "./vbrief-validation/index.js";
|
|
78
|
+
export * as verifyAc from "./verify-ac/index.js";
|
|
78
79
|
export * as verifyEnv from "./verify-env/index.js";
|
|
79
80
|
export * as verifySource from "./verify-source/index.js";
|
|
80
81
|
export * as wipCap from "./wip-cap/index.js";
|
|
@@ -6,12 +6,14 @@ import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/project
|
|
|
6
6
|
import { hasArtifactSuffix, resolveLifecycleRoot } from "../layout/resolve.js";
|
|
7
7
|
import { captureAndAttachLiteralAcceptance } from "../literal-acceptance/index.js";
|
|
8
8
|
import { stampAcceptanceFromLiteralCapture } from "../product-first-done-gate/index.js";
|
|
9
|
+
import { ENV_RUN_SUMMARY_PATH, RunSummaryEmitter } from "../run-summary/index.js";
|
|
9
10
|
import { call } from "../scm/call.js";
|
|
10
11
|
import { resolveProjectRoot } from "../scope/project-context.js";
|
|
11
12
|
import { resolveProjectRepo } from "../slice/project-context.js";
|
|
12
13
|
import { countMaintainerCurrentShapeComments, mapIssueCommentEntry, RAW_ISSUE_COMMENTS_KEY, selectCurrentShapeComment, } from "../umbrella-current-shape/index.js";
|
|
13
14
|
import { slugify, TODAY } from "../vbrief-build/build.js";
|
|
14
15
|
import { EMITTED_VBRIEF_VERSION } from "../vbrief-build/constants.js";
|
|
16
|
+
import { stampDerivedClausesOnAcceptance } from "../verify-ac/clauses.js";
|
|
15
17
|
import { LEGACY_ARTIFACT_SUFFIX, LEGACY_INFO_ROOT_KEY, MIGRATED_ARTIFACT_DIR, MIGRATED_ARTIFACT_SUFFIX, MIGRATED_INFO_ROOT_KEY, VBRIEF_VERSION, } from "../xbrief-migrate/constants.js";
|
|
16
18
|
import { findAcHeading, parseCheckboxItems, parseListItems, sliceAcSection, stripCodeBlocks, stripFencedCodeBlocks, } from "./markdown-scanners.js";
|
|
17
19
|
import { detectRepo, extractReferencesFromVbrief, fetchOpenIssues, GITHUB_ISSUE_REF_TYPES, LIFECYCLE_FOLDERS, parseIssueNumber, } from "./reconcile-issues.js";
|
|
@@ -475,6 +477,9 @@ export function buildIssueVbrief(issue, status, repoUrl, options = {}) {
|
|
|
475
477
|
Object.assign(plan, attached.plan);
|
|
476
478
|
// #3284: stamp plan.acceptance from captured literals (stated or none_stated floor).
|
|
477
479
|
Object.assign(plan, stampAcceptanceFromLiteralCapture(plan));
|
|
480
|
+
// #3323: when no commands were stated, derive numbered clauses before product edit.
|
|
481
|
+
const derived = stampDerivedClausesOnAcceptance(plan, [title, overviewSource].filter((s) => s.length > 0).join("\n\n"));
|
|
482
|
+
Object.assign(plan, derived.plan);
|
|
478
483
|
}
|
|
479
484
|
else {
|
|
480
485
|
// No body: still record none_stated acceptance so absence is a decision.
|
|
@@ -718,8 +723,45 @@ export function ingestOne(issue, options) {
|
|
|
718
723
|
assertWriteTargetSafe(projectRoot, target);
|
|
719
724
|
mkdirSync(folderPath, { recursive: true });
|
|
720
725
|
writeFileSync(target, `${JSON.stringify(vbrief, null, 2)}\n`, "utf8");
|
|
726
|
+
emitIntakeAcceptanceStamp(projectRoot, vbrief.plan);
|
|
721
727
|
return ["created", target, `CREATED ${folder}/${filename}`];
|
|
722
728
|
}
|
|
729
|
+
function emitIntakeAcceptanceStamp(projectRoot, plan) {
|
|
730
|
+
const rec = plan !== null && typeof plan === "object" && !Array.isArray(plan)
|
|
731
|
+
? plan
|
|
732
|
+
: null;
|
|
733
|
+
if (rec === null) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
const acceptance = rec.acceptance !== null && typeof rec.acceptance === "object" && !Array.isArray(rec.acceptance)
|
|
737
|
+
? rec.acceptance
|
|
738
|
+
: null;
|
|
739
|
+
if (acceptance === null) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const env = process.env;
|
|
743
|
+
const dest = env[ENV_RUN_SUMMARY_PATH];
|
|
744
|
+
if (dest === undefined || dest.trim().length === 0) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
try {
|
|
748
|
+
const sessionId = typeof env.DEFT_SESSION_ID === "string" && env.DEFT_SESSION_ID.trim().length > 0
|
|
749
|
+
? env.DEFT_SESSION_ID.trim()
|
|
750
|
+
: "issue-ingest";
|
|
751
|
+
const emitter = new RunSummaryEmitter({ projectRoot, sessionId, env });
|
|
752
|
+
const commands = Array.isArray(acceptance.commands) ? acceptance.commands.length : 0;
|
|
753
|
+
const clauses = Array.isArray(acceptance.clauses) ? acceptance.clauses.length : 0;
|
|
754
|
+
emitter.emitAcceptanceStamp({
|
|
755
|
+
rung: typeof acceptance.source_rung === "string" ? acceptance.source_rung : "project_floor",
|
|
756
|
+
none_stated: acceptance.none_stated === true,
|
|
757
|
+
command_count: commands,
|
|
758
|
+
clause_count: clauses,
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
catch {
|
|
762
|
+
// fail-open
|
|
763
|
+
}
|
|
764
|
+
}
|
|
723
765
|
export function ingestBulk(issues, options) {
|
|
724
766
|
let filtered = issues;
|
|
725
767
|
if (options.label !== undefined && options.label !== null) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ceremony-dial escalation evaluation + start-tier provenance (#3319).
|
|
3
|
+
*
|
|
4
|
+
* Observability only: does not change escalate-on-evidence thresholds or the
|
|
5
|
+
* default start tier. A declined evaluation is distinct from never-evaluated.
|
|
6
|
+
*/
|
|
7
|
+
import type { DialEscalationEvaluationOutcome } from "../run-summary/types.js";
|
|
8
|
+
import { type CeremonyDepth, type CeremonyDialInputs, type CeremonyDialSelection, type CeremonyModelTier } from "./ceremony-dial.js";
|
|
9
|
+
export declare const CEREMONY_START_TIER_PROVENANCES: readonly ["cold-start", "external-pin", "operator"];
|
|
10
|
+
export type CeremonyStartTierProvenance = (typeof CEREMONY_START_TIER_PROVENANCES)[number];
|
|
11
|
+
export declare const CEREMONY_DEPTH_RANK: Readonly<Record<CeremonyDepth, number>>;
|
|
12
|
+
export interface ResolveCeremonyStartTierProvenanceInput {
|
|
13
|
+
readonly selection: CeremonyDialSelection;
|
|
14
|
+
/** True when session:start received a pre-resolved selection (CLI/harness). */
|
|
15
|
+
readonly injectedSelection: boolean;
|
|
16
|
+
readonly hint?: CeremonyStartTierProvenance;
|
|
17
|
+
}
|
|
18
|
+
export declare function resolveCeremonyStartTierProvenance(input: ResolveCeremonyStartTierProvenanceInput): CeremonyStartTierProvenance;
|
|
19
|
+
export declare function isCeremonyStartTierPinned(provenance: CeremonyStartTierProvenance): boolean;
|
|
20
|
+
/** Session-start fail-closed line when a pin bypasses #3274 cold-start selection. */
|
|
21
|
+
export declare function formatCeremonyDialPinBypassLine(provenance: CeremonyStartTierProvenance): string | null;
|
|
22
|
+
export interface CeremonyDialEscalationEvaluation {
|
|
23
|
+
readonly tier: CeremonyDepth;
|
|
24
|
+
readonly outcome: DialEscalationEvaluationOutcome;
|
|
25
|
+
readonly reason: string;
|
|
26
|
+
readonly from: CeremonyDepth;
|
|
27
|
+
readonly to: CeremonyDepth;
|
|
28
|
+
}
|
|
29
|
+
export interface EvaluateCeremonyDialEscalationInput {
|
|
30
|
+
readonly from: CeremonyDepth;
|
|
31
|
+
readonly to: CeremonyDepth;
|
|
32
|
+
readonly inputs?: CeremonyDialInputs;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Pure escalate-on-evidence evaluation. `to > from` → escalated; else declined.
|
|
36
|
+
* Does not persist a transition.
|
|
37
|
+
*/
|
|
38
|
+
export declare function evaluateCeremonyDialEscalation(input: EvaluateCeremonyDialEscalationInput): CeremonyDialEscalationEvaluation;
|
|
39
|
+
/** Cold-start vs selected depth at session:start (unpinned path only). */
|
|
40
|
+
export declare function evaluateSessionStartCeremonyDialEscalation(input: {
|
|
41
|
+
readonly selection: CeremonyDialSelection;
|
|
42
|
+
readonly modelTier?: CeremonyModelTier | null;
|
|
43
|
+
}): CeremonyDialEscalationEvaluation;
|
|
44
|
+
export interface EmitCeremonyDialEscalationEvaluationOptions {
|
|
45
|
+
readonly projectRoot: string;
|
|
46
|
+
readonly sessionId: string;
|
|
47
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
48
|
+
readonly evaluation: CeremonyDialEscalationEvaluation;
|
|
49
|
+
}
|
|
50
|
+
/** Fail-open emit of a #3319 evaluation event. */
|
|
51
|
+
export declare function emitCeremonyDialEscalationEvaluation(options: EmitCeremonyDialEscalationEvaluationOptions): void;
|
|
52
|
+
//# sourceMappingURL=ceremony-dial-escalation.d.ts.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ceremony-dial escalation evaluation + start-tier provenance (#3319).
|
|
3
|
+
*
|
|
4
|
+
* Observability only: does not change escalate-on-evidence thresholds or the
|
|
5
|
+
* default start tier. A declined evaluation is distinct from never-evaluated.
|
|
6
|
+
*/
|
|
7
|
+
import { RunSummaryEmitter } from "../run-summary/emit.js";
|
|
8
|
+
import { selectCeremonyColdStartDepth, } from "./ceremony-dial.js";
|
|
9
|
+
export const CEREMONY_START_TIER_PROVENANCES = ["cold-start", "external-pin", "operator"];
|
|
10
|
+
export const CEREMONY_DEPTH_RANK = {
|
|
11
|
+
minimal: 0,
|
|
12
|
+
rapid: 1,
|
|
13
|
+
standard: 2,
|
|
14
|
+
elevated: 3,
|
|
15
|
+
};
|
|
16
|
+
export function resolveCeremonyStartTierProvenance(input) {
|
|
17
|
+
if (input.hint !== undefined) {
|
|
18
|
+
return input.hint;
|
|
19
|
+
}
|
|
20
|
+
if (input.selection.source === "override") {
|
|
21
|
+
return input.injectedSelection ? "external-pin" : "operator";
|
|
22
|
+
}
|
|
23
|
+
return "cold-start";
|
|
24
|
+
}
|
|
25
|
+
export function isCeremonyStartTierPinned(provenance) {
|
|
26
|
+
return provenance === "external-pin" || provenance === "operator";
|
|
27
|
+
}
|
|
28
|
+
/** Session-start fail-closed line when a pin bypasses #3274 cold-start selection. */
|
|
29
|
+
export function formatCeremonyDialPinBypassLine(provenance) {
|
|
30
|
+
if (!isCeremonyStartTierPinned(provenance)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const pinLabel = provenance === "external-pin" ? "external-pin" : "operator pin";
|
|
34
|
+
return (`[deft ceremony-dial] #3274 cold-start selection is bypassed (${pinLabel}). ` +
|
|
35
|
+
"Unset the pin (--ceremony-depth or plan.policy.ceremonyDial.override) to exercise #3274.");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Pure escalate-on-evidence evaluation. `to > from` → escalated; else declined.
|
|
39
|
+
* Does not persist a transition.
|
|
40
|
+
*/
|
|
41
|
+
export function evaluateCeremonyDialEscalation(input) {
|
|
42
|
+
const size = input.inputs?.taskSize ?? null;
|
|
43
|
+
const modelTier = input.inputs?.modelTier ?? null;
|
|
44
|
+
const evidence = `size=${size ?? "-"} modelTier=${modelTier ?? "-"}`;
|
|
45
|
+
const raised = CEREMONY_DEPTH_RANK[input.to] > CEREMONY_DEPTH_RANK[input.from];
|
|
46
|
+
if (raised) {
|
|
47
|
+
return {
|
|
48
|
+
tier: input.to,
|
|
49
|
+
outcome: "escalated",
|
|
50
|
+
reason: `evidence raised ${input.from} -> ${input.to} (${evidence})`,
|
|
51
|
+
from: input.from,
|
|
52
|
+
to: input.to,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
tier: input.from,
|
|
57
|
+
outcome: "declined",
|
|
58
|
+
reason: `insufficient evidence to raise above ${input.from} (${evidence})`,
|
|
59
|
+
from: input.from,
|
|
60
|
+
to: input.to,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Cold-start vs selected depth at session:start (unpinned path only). */
|
|
64
|
+
export function evaluateSessionStartCeremonyDialEscalation(input) {
|
|
65
|
+
const modelTier = input.modelTier ?? input.selection.inputs.modelTier;
|
|
66
|
+
const from = selectCeremonyColdStartDepth(modelTier);
|
|
67
|
+
return evaluateCeremonyDialEscalation({
|
|
68
|
+
from,
|
|
69
|
+
to: input.selection.depth,
|
|
70
|
+
inputs: input.selection.inputs,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** Fail-open emit of a #3319 evaluation event. */
|
|
74
|
+
export function emitCeremonyDialEscalationEvaluation(options) {
|
|
75
|
+
try {
|
|
76
|
+
const emitter = new RunSummaryEmitter({
|
|
77
|
+
projectRoot: options.projectRoot,
|
|
78
|
+
sessionId: options.sessionId,
|
|
79
|
+
env: options.env,
|
|
80
|
+
});
|
|
81
|
+
emitter.emitDialEscalationEvaluation({
|
|
82
|
+
tier: options.evaluation.tier,
|
|
83
|
+
outcome: options.evaluation.outcome,
|
|
84
|
+
reason: options.evaluation.reason,
|
|
85
|
+
});
|
|
86
|
+
emitter.emitKnownToolTurnDenominator();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// fail-open
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=ceremony-dial-escalation.js.map
|
|
@@ -161,7 +161,9 @@ export interface ResolveCeremonyDialOptions {
|
|
|
161
161
|
*/
|
|
162
162
|
export declare function resolveCeremonyDial(projectRoot: string, options?: ResolveCeremonyDialOptions): CeremonyDialSelection;
|
|
163
163
|
/** Human-readable status line for session:start / policy:show. */
|
|
164
|
-
export declare function formatCeremonyDialStatusLine(selection: CeremonyDialSelection
|
|
164
|
+
export declare function formatCeremonyDialStatusLine(selection: CeremonyDialSelection, extras?: {
|
|
165
|
+
readonly startTierProvenance?: string;
|
|
166
|
+
}): string;
|
|
165
167
|
/** JSON-serializable dial snapshot for ritual-state / session payload. */
|
|
166
168
|
export declare function ceremonyDialToDict(selection: CeremonyDialSelection): Record<string, unknown>;
|
|
167
169
|
export interface CeremonyDialPolicyField {
|
|
@@ -401,7 +401,7 @@ export function resolveCeremonyDial(projectRoot, options = {}) {
|
|
|
401
401
|
return selected;
|
|
402
402
|
}
|
|
403
403
|
/** Human-readable status line for session:start / policy:show. */
|
|
404
|
-
export function formatCeremonyDialStatusLine(selection) {
|
|
404
|
+
export function formatCeremonyDialStatusLine(selection, extras) {
|
|
405
405
|
const parts = [
|
|
406
406
|
`[deft ceremony-dial] depth=${selection.depth}`,
|
|
407
407
|
`source=${selection.source}`,
|
|
@@ -409,6 +409,10 @@ export function formatCeremonyDialStatusLine(selection) {
|
|
|
409
409
|
`modelTier=${selection.inputs.modelTier ?? "-"}`,
|
|
410
410
|
`projectShape=${selection.inputs.projectShape ?? "-"}`,
|
|
411
411
|
];
|
|
412
|
+
if (extras?.startTierProvenance !== undefined && extras.startTierProvenance.length > 0) {
|
|
413
|
+
parts.push(`start-tier=${selection.depth}`);
|
|
414
|
+
parts.push(`provenance=${extras.startTierProvenance}`);
|
|
415
|
+
}
|
|
412
416
|
if (selection.composition.rapidStrategy) {
|
|
413
417
|
parts.push(`compose=${selection.composition.rapidStrategy}`);
|
|
414
418
|
}
|
|
@@ -981,7 +985,49 @@ export function formatCeremonyDialAuditLine(audit) {
|
|
|
981
985
|
export function escalateCeremonyDial(projectRoot, options) {
|
|
982
986
|
const prior = resolveCeremonyDial(projectRoot);
|
|
983
987
|
const from = prior.depth;
|
|
988
|
+
const emitEscalationEvaluation = (applied, reasonSuffix) => {
|
|
989
|
+
if (options.emitRunSummary === false) {
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
try {
|
|
993
|
+
const audit = readCeremonyDialAudit(projectRoot);
|
|
994
|
+
const rawSid = audit.raw?.session_id;
|
|
995
|
+
const sid = options.sessionId ??
|
|
996
|
+
(typeof rawSid === "string" && rawSid.length > 0
|
|
997
|
+
? rawSid
|
|
998
|
+
: `dial-${Date.now().toString(36)}`);
|
|
999
|
+
const rank = {
|
|
1000
|
+
minimal: 0,
|
|
1001
|
+
rapid: 1,
|
|
1002
|
+
standard: 2,
|
|
1003
|
+
elevated: 3,
|
|
1004
|
+
};
|
|
1005
|
+
const raised = rank[options.to] > rank[from];
|
|
1006
|
+
const outcome = applied && raised ? "escalated" : "declined";
|
|
1007
|
+
const baseReason = options.confirm === true
|
|
1008
|
+
? options.reason
|
|
1009
|
+
: `${options.reason}; not applied (need --confirm)`;
|
|
1010
|
+
const reason = reasonSuffix !== undefined && reasonSuffix.length > 0
|
|
1011
|
+
? `${baseReason}; ${reasonSuffix}`
|
|
1012
|
+
: baseReason;
|
|
1013
|
+
const emitter = new RunSummaryEmitter({
|
|
1014
|
+
projectRoot,
|
|
1015
|
+
sessionId: sid,
|
|
1016
|
+
env: options.env,
|
|
1017
|
+
});
|
|
1018
|
+
emitter.emitDialEscalationEvaluation({
|
|
1019
|
+
tier: outcome === "escalated" ? options.to : from,
|
|
1020
|
+
outcome,
|
|
1021
|
+
reason,
|
|
1022
|
+
});
|
|
1023
|
+
emitter.emitKnownToolTurnDenominator();
|
|
1024
|
+
}
|
|
1025
|
+
catch {
|
|
1026
|
+
// fail-open
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
984
1029
|
if (options.confirm !== true) {
|
|
1030
|
+
emitEscalationEvaluation(false);
|
|
985
1031
|
return {
|
|
986
1032
|
exitCode: 1,
|
|
987
1033
|
from,
|
|
@@ -1001,6 +1047,8 @@ export function escalateCeremonyDial(projectRoot, options) {
|
|
|
1001
1047
|
note: options.note ?? `escalate: ${options.reason}`,
|
|
1002
1048
|
});
|
|
1003
1049
|
if (setResult.exitCode !== 0) {
|
|
1050
|
+
const persistDetail = oneLineAuditToken(setResult.stdout.trim().split("\n")[0] ?? `exit ${setResult.exitCode}`);
|
|
1051
|
+
emitEscalationEvaluation(false, `persist failed (exit ${setResult.exitCode}): ${persistDetail}`);
|
|
1004
1052
|
return {
|
|
1005
1053
|
exitCode: setResult.exitCode,
|
|
1006
1054
|
from,
|
|
@@ -1012,6 +1060,8 @@ export function escalateCeremonyDial(projectRoot, options) {
|
|
|
1012
1060
|
.filter((l) => l.length > 0),
|
|
1013
1061
|
};
|
|
1014
1062
|
}
|
|
1063
|
+
// #3319: evaluation event on every escalate path (applied or not).
|
|
1064
|
+
emitEscalationEvaluation(true);
|
|
1015
1065
|
// #3282: event-driven dial_transition line (fail-open).
|
|
1016
1066
|
if (options.emitRunSummary !== false) {
|
|
1017
1067
|
try {
|
|
@@ -1032,6 +1082,7 @@ export function escalateCeremonyDial(projectRoot, options) {
|
|
|
1032
1082
|
reason: options.reason,
|
|
1033
1083
|
evidence: options.evidence,
|
|
1034
1084
|
});
|
|
1085
|
+
emitter.emitKnownToolTurnDenominator();
|
|
1035
1086
|
}
|
|
1036
1087
|
catch {
|
|
1037
1088
|
// fail-open
|
|
@@ -1,52 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Check-resume / local suite-stamp policy (#3189).
|
|
2
|
+
* Check-resume / local suite-stamp policy (#3189 / #3314).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* stamp in v1 — `ciTrustsLocalStamp` is fixed false.
|
|
4
|
+
* Plain optional setting. Default off. Fail-closed when absent or invalid.
|
|
5
|
+
* Reserved — consumer expansion not implemented. CI never trusts a laptop stamp.
|
|
7
6
|
*/
|
|
8
7
|
/** Canonical registered policy field name. */
|
|
9
8
|
export declare const FIELD_CHECK_RESUME = "plan.policy.checkResume";
|
|
10
9
|
/** Short alias for `policy:show --field=checkResume`. */
|
|
11
10
|
export declare const FIELD_CHECK_RESUME_CLI_ALIAS = "checkResume";
|
|
12
|
-
export declare const CHECK_RESUME_STATUSES: readonly ["unset", "decided"];
|
|
13
|
-
export type CheckResumeStatus = (typeof CHECK_RESUME_STATUSES)[number];
|
|
14
11
|
export declare const CHECK_RESUME_LOCAL_STAMP: readonly ["off", "on"];
|
|
15
12
|
export type CheckResumeLocalStamp = (typeof CHECK_RESUME_LOCAL_STAMP)[number];
|
|
16
|
-
/** Fail-closed when
|
|
13
|
+
/** Fail-closed when absent / missing / invalid. */
|
|
17
14
|
export declare const DEFAULT_CHECK_RESUME_LOCAL_STAMP: CheckResumeLocalStamp;
|
|
18
|
-
/**
|
|
19
|
-
* FIXED false in v1 (#3189 non-goal). Separate RFC required to ever allow CI
|
|
20
|
-
* to trust a laptop suite stamp.
|
|
21
|
-
*/
|
|
22
|
-
export declare const CHECK_RESUME_CI_TRUSTS_LOCAL_STAMP_V1: false;
|
|
23
15
|
export interface CheckResumeConfig {
|
|
24
|
-
readonly status: CheckResumeStatus;
|
|
25
16
|
readonly localStamp: CheckResumeLocalStamp;
|
|
26
|
-
/** Always false in v1; present for schema visibility. */
|
|
27
|
-
readonly ciTrustsLocalStamp: false;
|
|
28
|
-
/** Present when decided via dismiss-with-reason. */
|
|
29
|
-
readonly dismissReason: string | null;
|
|
30
17
|
}
|
|
31
18
|
export type CheckResumeSource = "typed" | "default" | "default-on-error";
|
|
32
19
|
export interface CheckResumeResolved extends CheckResumeConfig {
|
|
33
20
|
readonly source: CheckResumeSource;
|
|
34
21
|
readonly error: string | null;
|
|
35
22
|
}
|
|
36
|
-
/** Validate a `plan.policy.checkResume` payload. */
|
|
23
|
+
/** Validate a `plan.policy.checkResume` payload. Extra keys are ignored. */
|
|
37
24
|
export declare function validateCheckResume(value: unknown): string[];
|
|
38
25
|
/**
|
|
39
|
-
* Resolve a typed block. Missing/invalid → localStamp off
|
|
40
|
-
*
|
|
41
|
-
* (malformed non-false is validation error → fail-closed default).
|
|
26
|
+
* Resolve a typed block. Missing/invalid → localStamp off.
|
|
27
|
+
* Leftover ritual fields (status/dismissReason/ciTrustsLocalStamp) are ignored.
|
|
42
28
|
*/
|
|
43
29
|
export declare function resolveCheckResumeFromTypedBlock(raw: unknown): CheckResumeResolved;
|
|
44
|
-
/** Resolve `plan.policy.checkResume` from PROJECT-DEFINITION (#
|
|
30
|
+
/** Resolve `plan.policy.checkResume` from PROJECT-DEFINITION (#3314). */
|
|
45
31
|
export declare function resolveCheckResume(projectRoot: string): CheckResumeResolved;
|
|
46
|
-
/** Local suite stamp resume only when
|
|
32
|
+
/** Local suite stamp resume only when localStamp=on. Reserved — unused by check/release. */
|
|
47
33
|
export declare function isLocalStampResumeAllowed(policy: CheckResumeResolved): boolean;
|
|
48
|
-
/** Always false in v1 — CI must re-run suite, never trust a laptop stamp. */
|
|
49
|
-
export declare function isCiTrustsLocalStampAllowed(_policy?: CheckResumeResolved): false;
|
|
50
34
|
export declare function formatCheckResumeStatusLine(policy: CheckResumeResolved): string;
|
|
51
35
|
export interface CheckResumePolicyField {
|
|
52
36
|
readonly name: typeof FIELD_CHECK_RESUME;
|
|
@@ -56,17 +40,4 @@ export interface CheckResumePolicyField {
|
|
|
56
40
|
}
|
|
57
41
|
/** Inspector row for `policy:show --field=checkResume`. */
|
|
58
42
|
export declare function inspectCheckResume(data: Record<string, unknown> | null, projectRoot?: string): CheckResumePolicyField;
|
|
59
|
-
export interface WriteCheckResumeOptions {
|
|
60
|
-
readonly localStamp: CheckResumeLocalStamp;
|
|
61
|
-
readonly dismissReason?: string | null;
|
|
62
|
-
readonly actor?: string;
|
|
63
|
-
readonly note?: string;
|
|
64
|
-
}
|
|
65
|
-
export interface WriteCheckResumeResult {
|
|
66
|
-
readonly exitCode: 0 | 2;
|
|
67
|
-
readonly stdout: string;
|
|
68
|
-
readonly changed: boolean;
|
|
69
|
-
}
|
|
70
|
-
/** Persist decided checkResume (preset or dismiss-with-reason). */
|
|
71
|
-
export declare function writeCheckResume(projectRoot: string, options: WriteCheckResumeOptions): WriteCheckResumeResult;
|
|
72
43
|
//# sourceMappingURL=check-resume.d.ts.map
|