@deftai/directive-core 0.101.0 → 0.103.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/init-deposit/hygiene.d.ts +7 -1
- package/dist/init-deposit/hygiene.js +11 -3
- package/dist/init-deposit/scaffold.d.ts +12 -0
- package/dist/init-deposit/scaffold.js +81 -8
- 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 +40 -2
- package/dist/product-first-done-gate/evaluate.js +253 -61
- package/dist/product-first-done-gate/index.d.ts +2 -1
- package/dist/product-first-done-gate/index.js +2 -1
- 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 +73 -0
- package/dist/verify-ac/evaluate.js +167 -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,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ritual+gate share from a #3282 run-summary stream (#3320).
|
|
3
|
+
*
|
|
4
|
+
* Share is ritual+gate invocations over the emitted tool/turn denominator.
|
|
5
|
+
* Absence of the denominator is unevaluable — never invent a share from counts.
|
|
6
|
+
*/
|
|
7
|
+
import { type RunSummaryLine } from "./types.js";
|
|
8
|
+
export interface RitualGateShare {
|
|
9
|
+
readonly evaluable: boolean;
|
|
10
|
+
readonly ritualGateCount: number;
|
|
11
|
+
readonly totalToolTurns: number | null;
|
|
12
|
+
readonly share: number | null;
|
|
13
|
+
}
|
|
14
|
+
/** True when n is a finite integer usable as a share denominator. */
|
|
15
|
+
export declare function isValidToolTurnDenominator(value: unknown): value is number;
|
|
16
|
+
/** Read total_tool_turns from a line (top-level field or payload). */
|
|
17
|
+
export declare function readToolTurnDenominator(line: unknown): number | undefined;
|
|
18
|
+
/** Parse JSONL (or DEFT-TLM: prefixed stdout capture) into run-summary lines. */
|
|
19
|
+
export declare function parseRunSummaryJsonl(text: string): RunSummaryLine[];
|
|
20
|
+
/**
|
|
21
|
+
* Compute ritual+gate share from summary lines alone.
|
|
22
|
+
* Uses the latest session in the stream. Missing/invalid denominator → unevaluable.
|
|
23
|
+
*/
|
|
24
|
+
export declare function computeRitualGateShare(lines: readonly RunSummaryLine[]): RitualGateShare;
|
|
25
|
+
//# sourceMappingURL=share.d.ts.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ritual+gate share from a #3282 run-summary stream (#3320).
|
|
3
|
+
*
|
|
4
|
+
* Share is ritual+gate invocations over the emitted tool/turn denominator.
|
|
5
|
+
* Absence of the denominator is unevaluable — never invent a share from counts.
|
|
6
|
+
*/
|
|
7
|
+
import { RUN_SUMMARY_STDOUT_PREFIX } from "./types.js";
|
|
8
|
+
function asRecord(value) {
|
|
9
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
/** True when n is a finite integer usable as a share denominator. */
|
|
15
|
+
export function isValidToolTurnDenominator(value) {
|
|
16
|
+
return (typeof value === "number" && Number.isInteger(value) && Number.isFinite(value) && value > 0);
|
|
17
|
+
}
|
|
18
|
+
/** Read total_tool_turns from a line (top-level field or payload). */
|
|
19
|
+
export function readToolTurnDenominator(line) {
|
|
20
|
+
const rec = asRecord(line);
|
|
21
|
+
if (rec === null) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
if (isValidToolTurnDenominator(rec.total_tool_turns)) {
|
|
25
|
+
return rec.total_tool_turns;
|
|
26
|
+
}
|
|
27
|
+
const payload = asRecord(rec.payload);
|
|
28
|
+
if (payload !== null && isValidToolTurnDenominator(payload.total_tool_turns)) {
|
|
29
|
+
return payload.total_tool_turns;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
function parseLine(raw) {
|
|
34
|
+
const trimmed = raw.trim();
|
|
35
|
+
if (trimmed.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const body = trimmed.startsWith(RUN_SUMMARY_STDOUT_PREFIX)
|
|
39
|
+
? trimmed.slice(RUN_SUMMARY_STDOUT_PREFIX.length)
|
|
40
|
+
: trimmed;
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(body);
|
|
43
|
+
const rec = asRecord(parsed);
|
|
44
|
+
if (rec === null) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
if (typeof rec.event !== "string" || typeof rec.session_id !== "string") {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return parsed;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Parse JSONL (or DEFT-TLM: prefixed stdout capture) into run-summary lines. */
|
|
57
|
+
export function parseRunSummaryJsonl(text) {
|
|
58
|
+
const lines = [];
|
|
59
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
60
|
+
const line = parseLine(raw);
|
|
61
|
+
if (line !== null) {
|
|
62
|
+
lines.push(line);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return lines;
|
|
66
|
+
}
|
|
67
|
+
function lastSessionId(lines) {
|
|
68
|
+
let lastStart = null;
|
|
69
|
+
let lastAny = null;
|
|
70
|
+
for (const line of lines) {
|
|
71
|
+
lastAny = line.session_id;
|
|
72
|
+
if (line.event === "session_start") {
|
|
73
|
+
lastStart = line.session_id;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return lastStart ?? lastAny;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Compute ritual+gate share from summary lines alone.
|
|
80
|
+
* Uses the latest session in the stream. Missing/invalid denominator → unevaluable.
|
|
81
|
+
*/
|
|
82
|
+
export function computeRitualGateShare(lines) {
|
|
83
|
+
const sessionId = lastSessionId(lines);
|
|
84
|
+
const sessionLines = sessionId === null ? [] : lines.filter((line) => line.session_id === sessionId);
|
|
85
|
+
let ritualGateCount = 0;
|
|
86
|
+
let totalToolTurns = null;
|
|
87
|
+
for (const line of sessionLines) {
|
|
88
|
+
if (line.event === "check_invocation") {
|
|
89
|
+
ritualGateCount += 1;
|
|
90
|
+
}
|
|
91
|
+
const denom = readToolTurnDenominator(line);
|
|
92
|
+
if (denom !== undefined) {
|
|
93
|
+
totalToolTurns = denom;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (totalToolTurns === null) {
|
|
97
|
+
return { evaluable: false, ritualGateCount, totalToolTurns: null, share: null };
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
evaluable: true,
|
|
101
|
+
ritualGateCount,
|
|
102
|
+
totalToolTurns,
|
|
103
|
+
share: ritualGateCount / totalToolTurns,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=share.js.map
|
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
export declare const RUN_SUMMARY_SCHEMA_VERSION: 1;
|
|
8
8
|
/** Env var that opts into / redirects run-summary JSONL (#3282). */
|
|
9
9
|
export declare const ENV_RUN_SUMMARY_PATH = "DEFT_RUN_SUMMARY_PATH";
|
|
10
|
+
/** Harness-supplied session tool/turn total stamped onto run-summary lines (#3320). */
|
|
11
|
+
export declare const ENV_TOTAL_TOOL_TURNS = "DEFT_TOTAL_TOOL_TURNS";
|
|
10
12
|
/** Repo-root default collectible path when gitignore coverage is present. */
|
|
11
13
|
export declare const DEFAULT_RUN_SUMMARY_BASENAME = ".deft-run-summary.json";
|
|
12
14
|
/** Prefix for stdout lines when `DEFT_RUN_SUMMARY_PATH=-`. */
|
|
13
15
|
export declare const RUN_SUMMARY_STDOUT_PREFIX = "DEFT-TLM:";
|
|
14
16
|
/** One warning when an explicitly requested write fails. */
|
|
15
17
|
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"];
|
|
18
|
+
export declare const RUN_SUMMARY_EVENT_KINDS: readonly ["session_start", "dial_transition", "dial_escalation_evaluation", "check_invocation", "tool_turn_denominator", "verification", "acceptance", "acceptance_stamp"];
|
|
17
19
|
export type RunSummaryEventKind = (typeof RUN_SUMMARY_EVENT_KINDS)[number];
|
|
18
20
|
export interface RunSummaryBaseFields {
|
|
19
21
|
readonly schema_version: typeof RUN_SUMMARY_SCHEMA_VERSION;
|
|
@@ -23,6 +25,11 @@ export interface RunSummaryBaseFields {
|
|
|
23
25
|
readonly seq: number;
|
|
24
26
|
readonly ts: string;
|
|
25
27
|
readonly event: RunSummaryEventKind;
|
|
28
|
+
/**
|
|
29
|
+
* Session total tool/turn count (#3320). Present so ritual+gate share is
|
|
30
|
+
* computable from the summary alone. Absence means the #3286 trigger is unevaluable.
|
|
31
|
+
*/
|
|
32
|
+
readonly total_tool_turns?: number;
|
|
26
33
|
}
|
|
27
34
|
export interface SessionStartRunSummaryPayload {
|
|
28
35
|
readonly ceremony_dial?: Record<string, unknown>;
|
|
@@ -43,6 +50,14 @@ export interface DialTransitionRunSummaryPayload {
|
|
|
43
50
|
readonly reason: string;
|
|
44
51
|
readonly evidence?: string;
|
|
45
52
|
}
|
|
53
|
+
/** One evaluation of escalate-on-evidence (#3319). Absence of this event ≠ declined. */
|
|
54
|
+
export type DialEscalationEvaluationOutcome = "escalated" | "declined";
|
|
55
|
+
export interface DialEscalationEvaluationRunSummaryPayload {
|
|
56
|
+
/** Ceremony depth considered (the start/current tier under evaluation). */
|
|
57
|
+
readonly tier: string;
|
|
58
|
+
readonly outcome: DialEscalationEvaluationOutcome;
|
|
59
|
+
readonly reason: string;
|
|
60
|
+
}
|
|
46
61
|
export interface CheckGateOutcome {
|
|
47
62
|
readonly id: string;
|
|
48
63
|
readonly status: "run" | "skipped" | "failed";
|
|
@@ -51,13 +66,56 @@ export interface CheckGateOutcome {
|
|
|
51
66
|
readonly remedy?: string;
|
|
52
67
|
readonly from_cache?: boolean;
|
|
53
68
|
}
|
|
69
|
+
/** Per-clause coverage row carried on verify:ac telemetry (#3323). */
|
|
70
|
+
export interface AcceptanceClauseOutcomeRow {
|
|
71
|
+
readonly id: number;
|
|
72
|
+
readonly outcome: "verified" | "unverifiable" | "failed";
|
|
73
|
+
}
|
|
54
74
|
export interface CheckInvocationRunSummaryPayload {
|
|
55
75
|
readonly target: string;
|
|
56
76
|
readonly exit_code: number;
|
|
57
77
|
readonly degraded?: boolean;
|
|
58
78
|
readonly gates: readonly CheckGateOutcome[];
|
|
79
|
+
/** Additive verify:ac fields (#3323). Consumers ignore unknown keys. */
|
|
80
|
+
readonly source_rung?: string;
|
|
81
|
+
readonly none_stated?: boolean;
|
|
82
|
+
readonly clause_outcomes?: readonly AcceptanceClauseOutcomeRow[];
|
|
83
|
+
}
|
|
84
|
+
/** Total tool/turn count for the session (#3320). */
|
|
85
|
+
export interface ToolTurnDenominatorRunSummaryPayload {
|
|
86
|
+
readonly total_tool_turns: number;
|
|
87
|
+
}
|
|
88
|
+
/** Product-oracle attempt (#3322). Same emitter as #3319 / #3320. */
|
|
89
|
+
export type VerificationOutcome = "pass" | "fail";
|
|
90
|
+
/** verify:ac resolution telemetry (#3334). Distinct from verification pass/fail. */
|
|
91
|
+
export type AcceptanceRunSummaryOutcome = "verified-pass" | "empty-pass" | "soft_empty" | "fail";
|
|
92
|
+
export interface AcceptanceRunSummaryPayload {
|
|
93
|
+
readonly resolved_command_count: number;
|
|
94
|
+
readonly outcome: AcceptanceRunSummaryOutcome;
|
|
95
|
+
readonly source_rung?: string;
|
|
96
|
+
readonly none_stated?: boolean;
|
|
97
|
+
readonly clause_count?: number;
|
|
98
|
+
readonly clause_outcomes?: readonly AcceptanceClauseOutcomeRow[];
|
|
99
|
+
}
|
|
100
|
+
/** Intake-time stamp: which rung locked, whether commands were stated, counts (#3323). */
|
|
101
|
+
export interface AcceptanceStampRunSummaryPayload {
|
|
102
|
+
readonly rung: string;
|
|
103
|
+
readonly none_stated: boolean;
|
|
104
|
+
readonly command_count: number;
|
|
105
|
+
readonly clause_count: number;
|
|
106
|
+
}
|
|
107
|
+
export interface VerificationRunSummaryPayload {
|
|
108
|
+
readonly check_id: string;
|
|
109
|
+
readonly method_fingerprint: string;
|
|
110
|
+
readonly outcome: VerificationOutcome;
|
|
111
|
+
/**
|
|
112
|
+
* True when both sides of the comparison were rebuilt from scratch by a
|
|
113
|
+
* different method than the one that failed. Required to resolve
|
|
114
|
+
* fail → method-change → pass (#3322).
|
|
115
|
+
*/
|
|
116
|
+
readonly independent_rederivation?: boolean;
|
|
59
117
|
}
|
|
60
|
-
export type RunSummaryPayload = SessionStartRunSummaryPayload | DialTransitionRunSummaryPayload | CheckInvocationRunSummaryPayload;
|
|
118
|
+
export type RunSummaryPayload = SessionStartRunSummaryPayload | DialTransitionRunSummaryPayload | DialEscalationEvaluationRunSummaryPayload | CheckInvocationRunSummaryPayload | ToolTurnDenominatorRunSummaryPayload | VerificationRunSummaryPayload | AcceptanceRunSummaryPayload | AcceptanceStampRunSummaryPayload;
|
|
61
119
|
export type RunSummaryLine = RunSummaryBaseFields & {
|
|
62
120
|
readonly payload: RunSummaryPayload;
|
|
63
121
|
};
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
export const RUN_SUMMARY_SCHEMA_VERSION = 1;
|
|
8
8
|
/** Env var that opts into / redirects run-summary JSONL (#3282). */
|
|
9
9
|
export const ENV_RUN_SUMMARY_PATH = "DEFT_RUN_SUMMARY_PATH";
|
|
10
|
+
/** Harness-supplied session tool/turn total stamped onto run-summary lines (#3320). */
|
|
11
|
+
export const ENV_TOTAL_TOOL_TURNS = "DEFT_TOTAL_TOOL_TURNS";
|
|
10
12
|
/** Repo-root default collectible path when gitignore coverage is present. */
|
|
11
13
|
export const DEFAULT_RUN_SUMMARY_BASENAME = ".deft-run-summary.json";
|
|
12
14
|
/** Prefix for stdout lines when `DEFT_RUN_SUMMARY_PATH=-`. */
|
|
@@ -16,6 +18,11 @@ export const RUN_SUMMARY_WRITE_WARNING = "[deft run-summary] failed to write DEF
|
|
|
16
18
|
export const RUN_SUMMARY_EVENT_KINDS = [
|
|
17
19
|
"session_start",
|
|
18
20
|
"dial_transition",
|
|
21
|
+
"dial_escalation_evaluation",
|
|
19
22
|
"check_invocation",
|
|
23
|
+
"tool_turn_denominator",
|
|
24
|
+
"verification",
|
|
25
|
+
"acceptance",
|
|
26
|
+
"acceptance_stamp",
|
|
20
27
|
];
|
|
21
28
|
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scope:activate refuses acceptance-shaped narratives without plan.acceptance (#3334).
|
|
3
|
+
*
|
|
4
|
+
* Agents author Test / AcceptanceCriteria / Verification prose in narratives
|
|
5
|
+
* and then skip the executable plan.acceptance block. Activation fails closed
|
|
6
|
+
* with one remediation: stamp the acceptance block.
|
|
7
|
+
*/
|
|
8
|
+
export interface AcceptanceActivateHit {
|
|
9
|
+
readonly key: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AcceptanceActivateGateResult {
|
|
12
|
+
readonly ok: boolean;
|
|
13
|
+
readonly message: string;
|
|
14
|
+
readonly hits: readonly AcceptanceActivateHit[];
|
|
15
|
+
}
|
|
16
|
+
/** Narrative keys that look like authored acceptance (non-empty string values). */
|
|
17
|
+
export declare function collectAcceptanceShapedNarrativeKeys(narratives: Record<string, unknown>): AcceptanceActivateHit[];
|
|
18
|
+
/**
|
|
19
|
+
* Fail closed when narratives carry acceptance-shaped keys and plan.acceptance
|
|
20
|
+
* is absent. A stamped (even empty/none_stated) block is enough.
|
|
21
|
+
*/
|
|
22
|
+
export declare function evaluateAcceptanceActivateGate(plan: Record<string, unknown>): AcceptanceActivateGateResult;
|
|
23
|
+
//# sourceMappingURL=acceptance-activate-gate.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scope:activate refuses acceptance-shaped narratives without plan.acceptance (#3334).
|
|
3
|
+
*
|
|
4
|
+
* Agents author Test / AcceptanceCriteria / Verification prose in narratives
|
|
5
|
+
* and then skip the executable plan.acceptance block. Activation fails closed
|
|
6
|
+
* with one remediation: stamp the acceptance block.
|
|
7
|
+
*/
|
|
8
|
+
import { validatePlanAcceptance } from "../product-first-done-gate/acceptance.js";
|
|
9
|
+
function asRecord(value) {
|
|
10
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const ACCEPTANCE_SHAPED_KEYS = new Set(["test", "acceptancecriteria", "verification"]);
|
|
16
|
+
function normalizeNarrativeKey(key) {
|
|
17
|
+
return key.replace(/[\s_-]+/g, "").toLowerCase();
|
|
18
|
+
}
|
|
19
|
+
/** Narrative keys that look like authored acceptance (non-empty string values). */
|
|
20
|
+
export function collectAcceptanceShapedNarrativeKeys(narratives) {
|
|
21
|
+
const hits = [];
|
|
22
|
+
for (const key of Object.keys(narratives)) {
|
|
23
|
+
if (!ACCEPTANCE_SHAPED_KEYS.has(normalizeNarrativeKey(key))) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const value = narratives[key];
|
|
27
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
hits.push({ key });
|
|
31
|
+
}
|
|
32
|
+
return hits;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Fail closed when narratives carry acceptance-shaped keys and plan.acceptance
|
|
36
|
+
* is absent. A stamped (even empty/none_stated) block is enough.
|
|
37
|
+
*/
|
|
38
|
+
export function evaluateAcceptanceActivateGate(plan) {
|
|
39
|
+
const narratives = asRecord(plan.narratives);
|
|
40
|
+
if (narratives === null) {
|
|
41
|
+
return { ok: true, message: "", hits: [] };
|
|
42
|
+
}
|
|
43
|
+
const hits = collectAcceptanceShapedNarrativeKeys(narratives);
|
|
44
|
+
if (hits.length === 0) {
|
|
45
|
+
return { ok: true, message: "", hits: [] };
|
|
46
|
+
}
|
|
47
|
+
if (plan.acceptance !== undefined && plan.acceptance !== null) {
|
|
48
|
+
const schemaErrors = validatePlanAcceptance(plan.acceptance);
|
|
49
|
+
if (schemaErrors.length > 0) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
message: `Refusing activate: plan.acceptance is present but invalid (#3334): ` +
|
|
53
|
+
`${schemaErrors.join("; ")}. Stamp a valid plan.acceptance block ` +
|
|
54
|
+
`(author commands or none_stated via intake capture / task issue:ingest).`,
|
|
55
|
+
hits,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return { ok: true, message: "", hits };
|
|
59
|
+
}
|
|
60
|
+
const keys = hits.map((h) => h.key).join(", ");
|
|
61
|
+
return {
|
|
62
|
+
ok: false,
|
|
63
|
+
message: `Refusing activate: narratives contain acceptance-shaped keys (${keys}) ` +
|
|
64
|
+
`but plan.acceptance is absent (#3334). Stamp plan.acceptance ` +
|
|
65
|
+
`(author commands or none_stated via intake capture / task issue:ingest) — ` +
|
|
66
|
+
`the criteria are in the wrong, non-executable field.`,
|
|
67
|
+
hits,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=acceptance-activate-gate.js.map
|
package/dist/scope/index.d.ts
CHANGED
package/dist/scope/index.js
CHANGED
package/dist/scope/transition.js
CHANGED
|
@@ -5,6 +5,7 @@ import { assertProjectionContained, ProjectionContainmentError, } from "../fs/pr
|
|
|
5
5
|
import { hasArtifactSuffix } from "../layout/resolve.js";
|
|
6
6
|
import { evaluateCompletedPlanConsistency } from "../lifecycle/completed-consistency.js";
|
|
7
7
|
import { evaluateLiteralAcceptanceFromPlan } from "../literal-acceptance/index.js";
|
|
8
|
+
import { evaluateAcceptanceActivateGate } from "./acceptance-activate-gate.js";
|
|
8
9
|
import { evaluateAcceptanceEvidenceGate, formatAcceptanceCompletionListing, } from "./acceptance-evidence.js";
|
|
9
10
|
import { append, canonicalLogPath, newDecisionId } from "./audit-log.js";
|
|
10
11
|
import { atomicWriteBrief, formatBriefJson, readBriefForMutation } from "./brief-io.js";
|
|
@@ -148,6 +149,10 @@ export function runTransition(action, filePath, now = new Date(), options = {})
|
|
|
148
149
|
if (!effortGate.ok) {
|
|
149
150
|
return { ok: false, message: effortGate.message };
|
|
150
151
|
}
|
|
152
|
+
const acceptanceGate = evaluateAcceptanceActivateGate(planObj);
|
|
153
|
+
if (!acceptanceGate.ok) {
|
|
154
|
+
return { ok: false, message: acceptanceGate.message };
|
|
155
|
+
}
|
|
151
156
|
}
|
|
152
157
|
// #3041: fail closed before mutating a code-bearing complete without delivery evidence.
|
|
153
158
|
if (act === "complete") {
|
package/dist/session/index.d.ts
CHANGED
package/dist/session/index.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* agents:refresh and verify:cache-fresh; formats compact (opt-in) vs verbose
|
|
7
7
|
* (default). Does NOT implement unified `deft orient` (Later remains open).
|
|
8
8
|
*/
|
|
9
|
+
import { isFrameworkRepoRoot } from "../check/context.js";
|
|
9
10
|
import { decideThrottle, readState as readDoctorState, renderDoctorStatusLine, } from "../doctor/doctor-state.js";
|
|
10
11
|
import { cmdDoctor } from "../doctor/main.js";
|
|
11
12
|
import { applyAgentsRefresh } from "../platform/agents-md.js";
|
|
@@ -271,16 +272,23 @@ export function runCacheFreshOrientationSection(projectRoot, options) {
|
|
|
271
272
|
void options.now;
|
|
272
273
|
try {
|
|
273
274
|
const evaluate = options.evaluateFn ?? evaluateCacheFresh;
|
|
274
|
-
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
275
|
+
const consumerDeposit = !isFrameworkRepoRoot(projectRoot);
|
|
276
|
+
// Consumer deposits often have no triage cache. Treat that as a named
|
|
277
|
+
// bootstrap cause (dirty), never a generic orientation `error` (#3335).
|
|
278
|
+
// Framework source still evaluates live; missing cache stays non-green
|
|
279
|
+
// (#3286) so gated verify re-runs cache_fresh.
|
|
278
280
|
const result = evaluate(projectRoot, {
|
|
279
281
|
allowMissingBootstrap: false,
|
|
280
282
|
autoPopulateEmpty: false,
|
|
281
283
|
...options.evaluateOptions,
|
|
282
284
|
});
|
|
283
285
|
const ok = result.code === 0;
|
|
286
|
+
const missingCache = result.code === 2 && /not found|bootstrap/i.test(result.message);
|
|
287
|
+
const namedCause = missingCache
|
|
288
|
+
? consumerDeposit
|
|
289
|
+
? `[deft cache-fresh] triage cache not populated (consumer deposit) — not a toolchain failure. Recovery: run \`deft triage:bootstrap\` if you need the queue.`
|
|
290
|
+
: result.message
|
|
291
|
+
: result.message;
|
|
284
292
|
// Tag as sha_match only when message already uses the canonical phrase
|
|
285
293
|
// (e.g. tests inject it) — never invent a shortcut past evaluate.
|
|
286
294
|
const shaMatch = ok && result.message.includes(DEPOSIT_SHA_MATCH_NOOP);
|
|
@@ -288,19 +296,21 @@ export function runCacheFreshOrientationSection(projectRoot, options) {
|
|
|
288
296
|
? "sha_match"
|
|
289
297
|
: ok
|
|
290
298
|
? "ok"
|
|
291
|
-
:
|
|
292
|
-
? "
|
|
293
|
-
:
|
|
299
|
+
: missingCache
|
|
300
|
+
? "dirty"
|
|
301
|
+
: result.code === 2
|
|
302
|
+
? "error"
|
|
303
|
+
: "dirty";
|
|
294
304
|
return {
|
|
295
305
|
name: "cache_fresh",
|
|
296
306
|
status,
|
|
297
307
|
ok,
|
|
298
308
|
exitCode: result.code,
|
|
299
|
-
lines: [
|
|
309
|
+
lines: [namedCause],
|
|
300
310
|
shaMatch,
|
|
301
311
|
depositSha: options.depositSha,
|
|
302
312
|
durationMs: elapsedMs(started),
|
|
303
|
-
detail: { code: result.code },
|
|
313
|
+
detail: { code: result.code, missing_cache: missingCache },
|
|
304
314
|
};
|
|
305
315
|
}
|
|
306
316
|
catch (exc) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type HostContentSurfaceSeams } from "../platform/host-content-surface.js";
|
|
2
2
|
import { type EnvironmentContext } from "../platform/shell-context.js";
|
|
3
3
|
import { type CeremonyDialInputs, type CeremonyDialSelection, type ProvisionalCeremonyEstimateHints } from "../policy/ceremony-dial.js";
|
|
4
|
+
import { type CeremonyStartTierProvenance } from "../policy/ceremony-dial-escalation.js";
|
|
4
5
|
import { type ProbeScmReadinessOptions, type ScmReadinessReport } from "../scm/readiness.js";
|
|
5
6
|
import { type ResolveUserMdResult } from "../user-config/resolve-user-md.js";
|
|
6
7
|
import { type DetectHardEffortBudgetInput } from "./effort-budget.js";
|
|
@@ -125,6 +126,11 @@ export interface SessionStartOptions {
|
|
|
125
126
|
* loads plan.policy.ceremonyDial and applies inputs (after provisional fill).
|
|
126
127
|
*/
|
|
127
128
|
readonly ceremonyDial?: CeremonyDialSelection;
|
|
129
|
+
/**
|
|
130
|
+
* #3319: start-tier provenance hint. CLI `--ceremony-depth` / harness pin
|
|
131
|
+
* should pass `external-pin`. Policy override is inferred as `operator`.
|
|
132
|
+
*/
|
|
133
|
+
readonly ceremonyDialStartTierProvenance?: CeremonyStartTierProvenance;
|
|
128
134
|
/**
|
|
129
135
|
* #3282: done-gate toolchain preflight seams (tests inject result or probe).
|
|
130
136
|
* When omitted, runs live preflight after verify_tools on cold path.
|
|
@@ -7,6 +7,8 @@ import { MIGRATE_COMPLETION_NUDGE, shouldEmitMigrateNudge } from "../init-deposi
|
|
|
7
7
|
import { hostContentSurfaceToDict, maybeFormatHostContentSurfaceLines, } from "../platform/host-content-surface.js";
|
|
8
8
|
import { detectEnvironmentContext, environmentContextToDict, formatEnvironmentContext, } from "../platform/shell-context.js";
|
|
9
9
|
import { ceremonyDialToDict, formatCeremonyDialStatusLine, mergeCeremonyDialDeferrals, resolveCeremonyDial, resolveSessionCeremonyDialInputs, } from "../policy/ceremony-dial.js";
|
|
10
|
+
import { emitCeremonyDialEscalationEvaluation, evaluateSessionStartCeremonyDialEscalation, formatCeremonyDialPinBypassLine, isCeremonyStartTierPinned, resolveCeremonyStartTierProvenance, } from "../policy/ceremony-dial-escalation.js";
|
|
11
|
+
import { maybeFormatCoverageCheckResumeDisclosure } from "../policy/coverage-debt.js";
|
|
10
12
|
import { DEFT_DIRECTIVE_DISABLE_FLAG_NAME, DEFT_DIRECTIVE_DISABLE_STATUS, detectDeftDirectiveDisable, formatDeftDirectiveDisableMessage, isDeftDirectiveDisableActive, } from "../policy/deft-directive-disable.js";
|
|
11
13
|
import { disclosureLine } from "../policy/disclosure.js";
|
|
12
14
|
import { detectNoDeftDirective, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRECTIVE_FLAG_NAME, NO_DEFT_DIRECTIVE_INCONSISTENT_MESSAGE, NO_DEFT_DIRECTIVE_INCONSISTENT_POLICY, } from "../policy/no-deft-directive.js";
|
|
@@ -21,7 +23,6 @@ import { runDefaultMode } from "../triage/welcome/default-mode.js";
|
|
|
21
23
|
import { resolveUserMdPath } from "../user-config/resolve-user-md.js";
|
|
22
24
|
import { emitSessionValueReadback } from "../value/readback.js";
|
|
23
25
|
import { verifyRequiredTools } from "../verify-env/verify-tools.js";
|
|
24
|
-
import { maybeFormatCoverageCheckResumeNudge } from "./coverage-check-resume-nudge.js";
|
|
25
26
|
import { effortBudgetToDict, maybeFormatEffortBudgetLines, resolveProductionHostEffortDescriptor, } from "./effort-budget.js";
|
|
26
27
|
import { defaultGitRunner, gitHead, gitIsAncestor, worktreePath } from "./git.js";
|
|
27
28
|
import { runOrientationCompression, } from "./orientation-compression.js";
|
|
@@ -48,6 +49,18 @@ export const QUICK_STEPS = [
|
|
|
48
49
|
"verify_tools",
|
|
49
50
|
];
|
|
50
51
|
export const GATED_STEPS = ["agent_hooks", "doctor", "cache_fresh"];
|
|
52
|
+
/** Standing one-liner when coverageDebt/checkResume is non-default (#3314). */
|
|
53
|
+
function pushCoverageCheckResumeDisclosure(lines, projectRoot) {
|
|
54
|
+
try {
|
|
55
|
+
const line = maybeFormatCoverageCheckResumeDisclosure(projectRoot);
|
|
56
|
+
if (line !== null) {
|
|
57
|
+
lines.push(line);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// best-effort — ritual must not abort
|
|
62
|
+
}
|
|
63
|
+
}
|
|
51
64
|
/** Env opt-in for optional session:start network (release probe + triage cache hydrate) (#2991). */
|
|
52
65
|
export const ENV_SESSION_START_NETWORK = "DEFT_SESSION_START_NETWORK";
|
|
53
66
|
/** Human-readable skip notice when optional network is off the hot path (#2991). */
|
|
@@ -527,16 +540,7 @@ function runSessionRearm(projectRoot, options, instant, environment) {
|
|
|
527
540
|
if (humanMergeLine !== null) {
|
|
528
541
|
lines.push(humanMergeLine);
|
|
529
542
|
}
|
|
530
|
-
|
|
531
|
-
try {
|
|
532
|
-
const coverageNudge = maybeFormatCoverageCheckResumeNudge({ projectRoot });
|
|
533
|
-
if (coverageNudge.length > 0) {
|
|
534
|
-
lines.push(coverageNudge.trimEnd());
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
catch {
|
|
538
|
-
// best-effort — re-arm must not abort
|
|
539
|
-
}
|
|
543
|
+
pushCoverageCheckResumeDisclosure(lines, projectRoot);
|
|
540
544
|
const priorQuick = eligibility.state.quickSteps;
|
|
541
545
|
const priorTriage = priorQuick.triage_welcome ?? ritualStep({ ok: true, ts: instant });
|
|
542
546
|
// Greptile P1: legacy ritual-state without verify_tools must re-run tools —
|
|
@@ -802,6 +806,11 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
802
806
|
env: options.env,
|
|
803
807
|
});
|
|
804
808
|
const ceremonyDialSelection = options.ceremonyDial ?? resolveCeremonyDial(projectRoot, { inputs: resolvedDialInputs });
|
|
809
|
+
const startTierProvenance = resolveCeremonyStartTierProvenance({
|
|
810
|
+
selection: ceremonyDialSelection,
|
|
811
|
+
injectedSelection: options.ceremonyDial !== undefined,
|
|
812
|
+
hint: options.ceremonyDialStartTierProvenance,
|
|
813
|
+
});
|
|
805
814
|
const effectiveDeferrals = mergeCeremonyDialDeferrals(deferrals, ceremonyDialSelection);
|
|
806
815
|
const skipFatPath = ceremonyDialSelection.profile.skipFatPath;
|
|
807
816
|
const { head: gitHeadValue, error: gitError } = gitHead(projectRoot, runGit);
|
|
@@ -831,7 +840,13 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
831
840
|
const quickSteps = recordDeferredSteps(QUICK_STEPS, effectiveDeferrals, instant);
|
|
832
841
|
const gatedSteps = recordDeferredSteps(GATED_STEPS, effectiveDeferrals, instant);
|
|
833
842
|
const lines = [];
|
|
834
|
-
lines.push(formatCeremonyDialStatusLine(ceremonyDialSelection
|
|
843
|
+
lines.push(formatCeremonyDialStatusLine(ceremonyDialSelection, {
|
|
844
|
+
startTierProvenance,
|
|
845
|
+
}));
|
|
846
|
+
const pinBypassLine = formatCeremonyDialPinBypassLine(startTierProvenance);
|
|
847
|
+
if (pinBypassLine !== null) {
|
|
848
|
+
lines.push(pinBypassLine);
|
|
849
|
+
}
|
|
835
850
|
if (provisionalDial.reasons.length > 0 && options.ceremonyDial === undefined) {
|
|
836
851
|
lines.push(`[deft ceremony-dial] provisional: ${provisionalDial.reasons.join("; ")}`);
|
|
837
852
|
}
|
|
@@ -919,6 +934,8 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
919
934
|
else {
|
|
920
935
|
stepTimings.push({ name: "branch_policy", duration_ms: 0, skipped: true });
|
|
921
936
|
}
|
|
937
|
+
// Standing disclosure is independent of branch_policy deferral (#3314 / Greptile).
|
|
938
|
+
pushCoverageCheckResumeDisclosure(lines, projectRoot);
|
|
922
939
|
// #3214 / #3156: verify_tools is mutation readiness — always run, even under
|
|
923
940
|
// rapid/minimal. Dial skipFatPath only lightens *ceremony* (triage welcome,
|
|
924
941
|
// optional network, staleness tickler), never readiness gates.
|
|
@@ -1182,20 +1199,12 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
1182
1199
|
if (consentPrompt.length > 0) {
|
|
1183
1200
|
lines.push(consentPrompt.trimEnd());
|
|
1184
1201
|
}
|
|
1185
|
-
// #3189: skippable coverageDebt/checkResume project-decision nudge (fail-open; never blocks).
|
|
1186
|
-
try {
|
|
1187
|
-
const coverageNudge = maybeFormatCoverageCheckResumeNudge({ projectRoot });
|
|
1188
|
-
if (coverageNudge.length > 0) {
|
|
1189
|
-
lines.push(coverageNudge.trimEnd());
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
catch {
|
|
1193
|
-
// best-effort operator advisory — session start must not abort
|
|
1194
|
-
}
|
|
1195
1202
|
const writeStarted = performance.now();
|
|
1196
1203
|
const coldSessionId = (options.newSessionId ?? randomUUID)();
|
|
1197
1204
|
const dialDict = {
|
|
1198
1205
|
...ceremonyDialToDict(ceremonyDialSelection),
|
|
1206
|
+
start_tier: ceremonyDialSelection.depth,
|
|
1207
|
+
start_tier_provenance: startTierProvenance,
|
|
1199
1208
|
provisional: {
|
|
1200
1209
|
taskSize: provisionalDial.taskSize,
|
|
1201
1210
|
modelTier: provisionalDial.modelTier,
|
|
@@ -1274,6 +1283,19 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
1274
1283
|
}
|
|
1275
1284
|
: {}),
|
|
1276
1285
|
});
|
|
1286
|
+
emitter.emitKnownToolTurnDenominator();
|
|
1287
|
+
// #3319: evaluate escalate-on-evidence only when #3274 is live. A pin
|
|
1288
|
+
// emits nothing so never-evaluated stays distinguishable from declined.
|
|
1289
|
+
if (!isCeremonyStartTierPinned(startTierProvenance)) {
|
|
1290
|
+
emitCeremonyDialEscalationEvaluation({
|
|
1291
|
+
projectRoot,
|
|
1292
|
+
sessionId: coldSessionId,
|
|
1293
|
+
env: options.env,
|
|
1294
|
+
evaluation: evaluateSessionStartCeremonyDialEscalation({
|
|
1295
|
+
selection: ceremonyDialSelection,
|
|
1296
|
+
}),
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1277
1299
|
}
|
|
1278
1300
|
catch {
|
|
1279
1301
|
// fail-open
|
|
@@ -8,9 +8,12 @@
|
|
|
8
8
|
* Never bootstraps tooling the PRODUCT does not need. Failures name cause and
|
|
9
9
|
* remedy without embedding env values.
|
|
10
10
|
*/
|
|
11
|
+
import { type CheckGateSpec } from "../check/gate-lists.js";
|
|
11
12
|
export declare const TOOLCHAIN_PREFLIGHT_TOOLS: readonly ["task", "pnpm", "node", "git"];
|
|
12
13
|
export type ToolchainPreflightTool = (typeof TOOLCHAIN_PREFLIGHT_TOOLS)[number];
|
|
13
14
|
export type ToolchainPreflightStatus = "ok" | "missing" | "degraded";
|
|
15
|
+
/** How a missing tool affects check dispatch (#3335). */
|
|
16
|
+
export type ToolchainPreflightImpact = "none" | "degraded";
|
|
14
17
|
export interface ToolchainPreflightFinding {
|
|
15
18
|
readonly tool: ToolchainPreflightTool | "cli_dist";
|
|
16
19
|
readonly present: boolean;
|
|
@@ -18,6 +21,11 @@ export interface ToolchainPreflightFinding {
|
|
|
18
21
|
readonly cause: string | null;
|
|
19
22
|
/** Operator/agent remedy command or instruction. */
|
|
20
23
|
readonly remedy: string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Missing-tool impact. `none` = present false but no install remedy and
|
|
26
|
+
* check does not skip CLI-native gates (#3335).
|
|
27
|
+
*/
|
|
28
|
+
readonly impact?: ToolchainPreflightImpact | null;
|
|
21
29
|
}
|
|
22
30
|
export interface ToolchainPreflightResult {
|
|
23
31
|
readonly status: ToolchainPreflightStatus;
|
|
@@ -46,6 +54,13 @@ export interface ToolchainPreflightOptions {
|
|
|
46
54
|
* a global `deft`/`directive` is on PATH.
|
|
47
55
|
*/
|
|
48
56
|
readonly probeCliDist?: boolean;
|
|
57
|
+
/** Active check composition. Defaults from consumer vs framework context. */
|
|
58
|
+
readonly composedGates?: readonly CheckGateSpec[];
|
|
59
|
+
/**
|
|
60
|
+
* Consumer deposit (not framework source). When omitted, inferred from
|
|
61
|
+
* frameworkRoot vs projectRoot (#3335 / #3324).
|
|
62
|
+
*/
|
|
63
|
+
readonly consumerDeposit?: boolean;
|
|
49
64
|
}
|
|
50
65
|
/**
|
|
51
66
|
* Gates that specifically need a package manager / built dist.
|