@deftai/directive-core 0.105.0 → 0.107.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 +591 -34
- package/dist/check/gate-lists.js +2 -0
- package/dist/check/named-cause.js +1 -1
- package/dist/design-critique/exclusive-chip.d.ts +33 -0
- package/dist/design-critique/exclusive-chip.js +68 -0
- package/dist/design-critique/parent-audit.d.ts +59 -0
- package/dist/design-critique/parent-audit.js +121 -0
- package/dist/doctor/checks.d.ts +6 -0
- package/dist/doctor/checks.js +35 -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/hooks/dest-form.d.ts +46 -0
- package/dist/hooks/dest-form.js +575 -0
- package/dist/hooks/dispatcher.d.ts +17 -1
- package/dist/hooks/dispatcher.js +82 -11
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +1 -1
- package/dist/intake/clause-derivation.d.ts +9 -0
- package/dist/intake/clause-derivation.js +30 -3
- package/dist/intake/github-auth-modes-cli.js +14 -2
- package/dist/intake/github-auth-modes.d.ts +54 -9
- package/dist/intake/github-auth-modes.js +326 -123
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +26 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +37 -14
- package/dist/lifecycle/completed-write-guard.d.ts +48 -0
- package/dist/lifecycle/completed-write-guard.js +373 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- 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 +16 -0
- package/dist/literal-acceptance/capture.js +78 -10
- package/dist/literal-acceptance/evaluate.js +25 -3
- package/dist/literal-acceptance/index.d.ts +2 -2
- package/dist/literal-acceptance/index.js +2 -2
- package/dist/literal-acceptance/run.js +9 -3
- package/dist/literal-acceptance/types.d.ts +6 -0
- package/dist/literal-acceptance/types.js +6 -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/policy/ceremony-dial.js +7 -7
- package/dist/policy/host-hooks.d.ts +20 -0
- package/dist/policy/host-hooks.js +121 -2
- 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/require-human-merge.js +8 -6
- package/dist/policy/resolve.d.ts +7 -2
- package/dist/policy/resolve.js +25 -8
- package/dist/policy/runtime-authority.d.ts +18 -0
- package/dist/policy/runtime-authority.js +11 -0
- package/dist/policy/value-feedback.js +7 -8
- package/dist/policy/write-fence.js +3 -0
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +24 -4
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/product-first-done-gate/evaluate.d.ts +4 -0
- package/dist/product-first-done-gate/evaluate.js +82 -10
- 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/types.d.ts +4 -0
- package/dist/scm/design-critique-chip.d.ts +37 -0
- package/dist/scm/design-critique-chip.js +171 -0
- package/dist/scm/index.d.ts +1 -0
- package/dist/scm/index.js +1 -0
- package/dist/scm/main.d.ts +3 -0
- package/dist/scm/main.js +15 -1
- package/dist/scm/readiness-cli.d.ts +2 -0
- package/dist/scm/readiness-cli.js +42 -1
- package/dist/scm/readiness.d.ts +2 -1
- package/dist/scm/readiness.js +7 -1
- package/dist/scope/decompose.js +2 -1
- package/dist/scope/delivery-evidence.d.ts +27 -1
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/lifecycle-write.d.ts +24 -0
- package/dist/scope/lifecycle-write.js +64 -0
- package/dist/scope/main.js +18 -6
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope/transition.js +90 -11
- package/dist/scope-provenance/evaluate.js +8 -4
- package/dist/session/ac-pass-banking.d.ts +5 -0
- package/dist/session/ac-pass-banking.js +3 -2
- package/dist/session/git.d.ts +18 -0
- package/dist/session/git.js +81 -1
- package/dist/session/occupancy.d.ts +2 -1
- package/dist/session/occupancy.js +11 -4
- package/dist/session/process-cost.d.ts +32 -10
- package/dist/session/process-cost.js +189 -1
- package/dist/session/product-state-hash.js +41 -24
- package/dist/session/ritual-entrypoint.js +16 -1
- package/dist/session/session-start.d.ts +18 -0
- package/dist/session/session-start.js +49 -2
- package/dist/session/verify-session-ritual.d.ts +46 -4
- package/dist/session/verify-session-ritual.js +118 -10
- 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 +14 -2
- package/dist/swarm/launch.d.ts +69 -0
- package/dist/swarm/launch.js +191 -1
- package/dist/swarm/routing-set-cli.js +2 -0
- package/dist/swarm/routing-verify.d.ts +1 -1
- package/dist/swarm/routing-verify.js +2 -2
- package/dist/triage/actions/index.d.ts +4 -0
- package/dist/triage/actions/index.js +6 -0
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/evaluate/evaluate.d.ts +11 -0
- package/dist/triage/evaluate/evaluate.js +169 -0
- package/dist/triage/evaluate/github.d.ts +16 -0
- package/dist/triage/evaluate/github.js +153 -0
- package/dist/triage/evaluate/index.d.ts +9 -0
- package/dist/triage/evaluate/index.js +8 -0
- package/dist/triage/evaluate/paths.d.ts +7 -0
- package/dist/triage/evaluate/paths.js +25 -0
- package/dist/triage/evaluate/sink.d.ts +5 -0
- package/dist/triage/evaluate/sink.js +52 -0
- package/dist/triage/evaluate/types.d.ts +93 -0
- package/dist/triage/evaluate/types.js +13 -0
- package/dist/triage/evaluate/validity.d.ts +8 -0
- package/dist/triage/evaluate/validity.js +87 -0
- package/dist/triage/evaluate/value.d.ts +12 -0
- package/dist/triage/evaluate/value.js +33 -0
- package/dist/triage/evaluate/wip-census.d.ts +5 -0
- package/dist/triage/evaluate/wip-census.js +39 -0
- package/dist/triage/evaluate/worktrees.d.ts +8 -0
- package/dist/triage/evaluate/worktrees.js +68 -0
- package/dist/triage/evaluate/xbrief-refs.d.ts +8 -0
- package/dist/triage/evaluate/xbrief-refs.js +60 -0
- package/dist/triage/help/registry-data.d.ts +22 -8
- package/dist/triage/help/registry-data.js +54 -6
- package/dist/triage/index.d.ts +1 -0
- package/dist/triage/index.js +1 -0
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/value/feedback-file.d.ts +17 -2
- package/dist/value/feedback-file.js +80 -6
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-reconcile/labels.d.ts +1 -0
- package/dist/vbrief-reconcile/labels.js +30 -0
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/vbrief-validation/story-quality.d.ts +7 -0
- package/dist/vbrief-validation/story-quality.js +8 -1
- 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/xbrief-migrate/agents-header.js +69 -7
- package/package.json +7 -3
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { type CheckIgnoreMatch, displayIgnoreSource, evaluateLifecycleVisible, formatLifecycleVisibleSessionLines, indexFlagKind, isSelectiveLifecyclePath, LIFECYCLE_ROOT_PREFIXES, LIFECYCLE_STAGE_DIRS, type LifecycleHideFinding, type LifecycleHideKind, type LifecycleVisibleOptions, type LifecycleVisibleResult, type LsFilesVerboseRecord, lifecycleRootRelPaths, parseCheckIgnoreVerboseLine, parseLsFilesVerboseRecord, } from "./evaluate.js";
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { displayIgnoreSource, evaluateLifecycleVisible, formatLifecycleVisibleSessionLines, indexFlagKind, isSelectiveLifecyclePath, LIFECYCLE_ROOT_PREFIXES, LIFECYCLE_STAGE_DIRS, lifecycleRootRelPaths, parseCheckIgnoreVerboseLine, parseLsFilesVerboseRecord, } from "./evaluate.js";
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -9,6 +9,17 @@
|
|
|
9
9
|
* so distinct execution contexts are not collapsed.
|
|
10
10
|
*/
|
|
11
11
|
import type { LiteralAcceptanceCommand, RejectedLiteralCommand } from "./types.js";
|
|
12
|
+
/** Reason stamped when an inline backtick is recorded as a mention, not AC (#3721). */
|
|
13
|
+
export declare const INLINE_PROSE_MENTION_REASON = "inline backtick in prose is a mention, not a stated acceptance command (#3721)";
|
|
14
|
+
/**
|
|
15
|
+
* True when a capture-only row came from an inline backtick in prose (#3721).
|
|
16
|
+
* Those mentions are not stated acceptance commands. Labeled, prompt, and fence
|
|
17
|
+
* spans stay stated.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isInlineProseMention(cmd: {
|
|
20
|
+
readonly source?: string;
|
|
21
|
+
readonly sourceSpan?: string | null;
|
|
22
|
+
}): boolean;
|
|
12
23
|
/** Result of capture including the operator-visible rejected ledger. */
|
|
13
24
|
export interface CaptureLiteralAcceptanceResult {
|
|
14
25
|
readonly commands: readonly LiteralAcceptanceCommand[];
|
|
@@ -57,6 +68,11 @@ export declare function isProseDerivedRejection(rejected: RejectedLiteralCommand
|
|
|
57
68
|
* prose-derived rejections no longer depends on this (#3511).
|
|
58
69
|
*/
|
|
59
70
|
export declare function hasStructuredAcceptanceCommands(plan: Record<string, unknown> | null | undefined): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Command strings the operator recorded as not acceptance commands (#3721).
|
|
73
|
+
* Listing a string here dispositions a capture without asserting it is AC.
|
|
74
|
+
*/
|
|
75
|
+
export declare function readNotAcceptanceCommands(plan: Record<string, unknown> | null | undefined): ReadonlySet<string>;
|
|
60
76
|
/** Format rejected ledger for CLI / complete-gate messages. */
|
|
61
77
|
export declare function formatRejectedLedger(rejected: readonly RejectedLiteralCommand[]): string;
|
|
62
78
|
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* so distinct execution contexts are not collapsed.
|
|
10
10
|
*/
|
|
11
11
|
import { evaluateCommandSafety } from "./safety.js";
|
|
12
|
-
import { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY } from "./types.js";
|
|
12
|
+
import { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_NOT_COMMANDS_METADATA_KEY, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY, } from "./types.js";
|
|
13
13
|
/** Labeled keywords (single-token, linear match). */
|
|
14
14
|
const LABELED_KEYWORDS = new Set(["verify", "command", "run", "check", "exec", "shell"]);
|
|
15
15
|
/** Words that look like a CLI invocation start (not prose). */
|
|
@@ -85,8 +85,24 @@ function pushCommand(buckets, cmd) {
|
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
const key = commandDedupeKey(cmd);
|
|
88
|
-
if (buckets.seen.has(key))
|
|
88
|
+
if (buckets.seen.has(key)) {
|
|
89
|
+
const idx = buckets.out.findIndex((row) => commandDedupeKey(row) === key);
|
|
90
|
+
const existing = idx >= 0 ? buckets.out[idx] : undefined;
|
|
91
|
+
if (existing !== undefined &&
|
|
92
|
+
idx >= 0 &&
|
|
93
|
+
isInlineProseMention(existing) &&
|
|
94
|
+
isExecutableSource(cmd.source)) {
|
|
95
|
+
buckets.out[idx] = {
|
|
96
|
+
command: cmd.command,
|
|
97
|
+
cwd: cmd.cwd ?? null,
|
|
98
|
+
expectedStdout: cmd.expectedStdout ?? null,
|
|
99
|
+
expectedExitCode: cmd.expectedExitCode ?? 0,
|
|
100
|
+
source: cmd.source,
|
|
101
|
+
sourceSpan: cmd.sourceSpan ?? null,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
89
104
|
return;
|
|
105
|
+
}
|
|
90
106
|
buckets.seen.add(key);
|
|
91
107
|
buckets.out.push({
|
|
92
108
|
command: cmd.command,
|
|
@@ -167,12 +183,12 @@ function matchLabeledCommand(line) {
|
|
|
167
183
|
return null;
|
|
168
184
|
return line.slice(i).trimEnd();
|
|
169
185
|
}
|
|
170
|
-
/** `$ cmd`
|
|
186
|
+
/** `$ cmd` prompt lines. Markdown blockquote `>` is not a prompt (#3572). */
|
|
171
187
|
function matchPromptCommand(line) {
|
|
172
188
|
let i = skipWs(line, 0);
|
|
173
189
|
if (i >= line.length)
|
|
174
190
|
return null;
|
|
175
|
-
if (line[i] !== "$"
|
|
191
|
+
if (line[i] !== "$")
|
|
176
192
|
return null;
|
|
177
193
|
i = skipWs(line, i + 1);
|
|
178
194
|
if (i >= line.length)
|
|
@@ -259,7 +275,7 @@ function flushFenceBody(body, fenceLang, fenceStartLine, requireRegion, regionAc
|
|
|
259
275
|
return;
|
|
260
276
|
if (!isShellFenceLang(fenceLang))
|
|
261
277
|
return;
|
|
262
|
-
// Transcript lines are skipped.
|
|
278
|
+
// Transcript lines are skipped. `$` prompts inside a transcript fence are
|
|
263
279
|
// suggested-fixes (biome migrate), not stated AC (#3511). Comments do not
|
|
264
280
|
// mark a fence as transcript, so a genuine command next to `# Error:` still
|
|
265
281
|
// captures.
|
|
@@ -382,8 +398,9 @@ function matchMarkdownHeading(line) {
|
|
|
382
398
|
* marker). Mid-line label capture is deliberately not attempted (#3484): a
|
|
383
399
|
* `verify:<verb>` token inside ordinary prose has no terminator, so the capture
|
|
384
400
|
* swallowed the rest of the paragraph and the phantom then blocked completion on
|
|
385
|
-
* the safety ledger. Commands stated mid-sentence must live in a fence
|
|
386
|
-
* prompt
|
|
401
|
+
* the safety ledger. Commands stated mid-sentence must live in a fence or a `$`
|
|
402
|
+
* prompt. An inline backtick inside a prose sentence is a reference, not a
|
|
403
|
+
* stated command (#3721).
|
|
387
404
|
*/
|
|
388
405
|
function extractFromLabeledLines(text, buckets) {
|
|
389
406
|
const lines = text.split(/\r?\n/);
|
|
@@ -412,9 +429,13 @@ function extractFromLabeledLines(text, buckets) {
|
|
|
412
429
|
}
|
|
413
430
|
}
|
|
414
431
|
}
|
|
432
|
+
/** Reason stamped when an inline backtick is recorded as a mention, not AC (#3721). */
|
|
433
|
+
export const INLINE_PROSE_MENTION_REASON = "inline backtick in prose is a mention, not a stated acceptance command (#3721)";
|
|
415
434
|
/**
|
|
416
435
|
* Extract inline `` `command` `` spans that follow verify/run language on the same line.
|
|
417
|
-
*
|
|
436
|
+
* These are references, not stated acceptance commands (#3721). Recorded on the
|
|
437
|
+
* rejected ledger with an `inline@` span so #3511 demotes them to advisory.
|
|
438
|
+
* They must not enter the stated-command list (that would require promotion).
|
|
418
439
|
*/
|
|
419
440
|
function extractInlineVerifySpans(text, buckets) {
|
|
420
441
|
const lines = text.split(/\r?\n/);
|
|
@@ -440,10 +461,23 @@ function extractInlineVerifySpans(text, buckets) {
|
|
|
440
461
|
const normalized = normalizeCommand(inner);
|
|
441
462
|
if (normalized === null || !looksLikeShellCommand(normalized))
|
|
442
463
|
continue;
|
|
443
|
-
|
|
464
|
+
recordRejected(buckets, normalized, INLINE_PROSE_MENTION_REASON, `inline@L${i + 1}`);
|
|
444
465
|
}
|
|
445
466
|
}
|
|
446
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* True when a capture-only row came from an inline backtick in prose (#3721).
|
|
470
|
+
* Those mentions are not stated acceptance commands. Labeled, prompt, and fence
|
|
471
|
+
* spans stay stated.
|
|
472
|
+
*/
|
|
473
|
+
export function isInlineProseMention(cmd) {
|
|
474
|
+
if (cmd.source !== "task_statement")
|
|
475
|
+
return false;
|
|
476
|
+
const span = cmd.sourceSpan;
|
|
477
|
+
if (span === null || span === undefined)
|
|
478
|
+
return false;
|
|
479
|
+
return span.startsWith("inline@");
|
|
480
|
+
}
|
|
447
481
|
function emptyBuckets() {
|
|
448
482
|
return {
|
|
449
483
|
out: [],
|
|
@@ -519,7 +553,7 @@ export function readStoredLiteralAcceptanceDetailed(plan) {
|
|
|
519
553
|
// swarm.verify_commands is a string list (legacy). Prefer richer
|
|
520
554
|
// literal_acceptance_commands rows already loaded — do not invent a
|
|
521
555
|
// null-cwd duplicate for the same command text.
|
|
522
|
-
const alreadyHasCommand = (command) => buckets.out.some((c) => c.command === command);
|
|
556
|
+
const alreadyHasCommand = (command) => buckets.out.some((c) => c.command === command && !isInlineProseMention(c));
|
|
523
557
|
for (const cmd of coerceCommandList(swarm.verify_commands, "verify_commands", "swarm.verify_commands")) {
|
|
524
558
|
if (alreadyHasCommand(cmd.command))
|
|
525
559
|
continue;
|
|
@@ -793,6 +827,40 @@ export function hasStructuredAcceptanceCommands(plan) {
|
|
|
793
827
|
return false;
|
|
794
828
|
return hasNonEmptyCommandList(swarm.verify_commands);
|
|
795
829
|
}
|
|
830
|
+
/**
|
|
831
|
+
* Command strings the operator recorded as not acceptance commands (#3721).
|
|
832
|
+
* Listing a string here dispositions a capture without asserting it is AC.
|
|
833
|
+
*/
|
|
834
|
+
export function readNotAcceptanceCommands(plan) {
|
|
835
|
+
const rec = asRecord(plan);
|
|
836
|
+
if (rec === null)
|
|
837
|
+
return new Set();
|
|
838
|
+
const metadata = asRecord(rec.metadata);
|
|
839
|
+
if (metadata === null)
|
|
840
|
+
return new Set();
|
|
841
|
+
const raw = metadata[LITERAL_ACCEPTANCE_NOT_COMMANDS_METADATA_KEY] ??
|
|
842
|
+
metadata.literalAcceptanceNotCommands ??
|
|
843
|
+
null;
|
|
844
|
+
const out = new Set();
|
|
845
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
846
|
+
out.add(raw.trim());
|
|
847
|
+
return out;
|
|
848
|
+
}
|
|
849
|
+
if (!Array.isArray(raw))
|
|
850
|
+
return out;
|
|
851
|
+
for (const entry of raw) {
|
|
852
|
+
if (typeof entry === "string" && entry.trim().length > 0) {
|
|
853
|
+
out.add(entry.trim());
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
const row = asRecord(entry);
|
|
857
|
+
if (row === null)
|
|
858
|
+
continue;
|
|
859
|
+
if (isNonEmptyString(row.command))
|
|
860
|
+
out.add(row.command.trim());
|
|
861
|
+
}
|
|
862
|
+
return out;
|
|
863
|
+
}
|
|
796
864
|
/** Format rejected ledger for CLI / complete-gate messages. */
|
|
797
865
|
export function formatRejectedLedger(rejected) {
|
|
798
866
|
if (rejected.length === 0)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
|
-
import { captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, isProseDerivedRejection, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
|
|
6
|
+
import { captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, INLINE_PROSE_MENTION_REASON, isInlineProseMention, isProseDerivedRejection, readNotAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
|
|
7
7
|
import { runLiteralAcceptanceCommands } from "./run.js";
|
|
8
8
|
function asRecord(value) {
|
|
9
9
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
@@ -40,11 +40,33 @@ function partitionRejected(rejected) {
|
|
|
40
40
|
*/
|
|
41
41
|
export function resolveLiteralAcceptanceDetailed(plan, options = {}) {
|
|
42
42
|
const raw = resolveRawLiteralAcceptance(plan, options);
|
|
43
|
+
const notCommands = readNotAcceptanceCommands(plan);
|
|
44
|
+
const stated = [];
|
|
45
|
+
const mentionAdvisory = [];
|
|
46
|
+
for (const c of raw.commands) {
|
|
47
|
+
if (isInlineProseMention(c)) {
|
|
48
|
+
mentionAdvisory.push({
|
|
49
|
+
command: c.command,
|
|
50
|
+
reason: INLINE_PROSE_MENTION_REASON,
|
|
51
|
+
sourceSpan: c.sourceSpan ?? null,
|
|
52
|
+
});
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (c.source === "task_statement" && notCommands.has(c.command)) {
|
|
56
|
+
mentionAdvisory.push({
|
|
57
|
+
command: c.command,
|
|
58
|
+
reason: "operator recorded this capture as not an acceptance command (#3721)",
|
|
59
|
+
sourceSpan: c.sourceSpan ?? null,
|
|
60
|
+
});
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
stated.push(c);
|
|
64
|
+
}
|
|
43
65
|
const split = partitionRejected(raw.rejected);
|
|
44
66
|
return {
|
|
45
|
-
commands:
|
|
67
|
+
commands: stated,
|
|
46
68
|
rejected: split.blocking,
|
|
47
|
-
advisoryRejected: split.advisory,
|
|
69
|
+
advisoryRejected: [...split.advisory, ...mentionAdvisory],
|
|
48
70
|
transcriptPromptSkipped: raw.transcriptPromptSkipped,
|
|
49
71
|
};
|
|
50
72
|
}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Capture exact stated shell commands at intake; run them verbatim before done.
|
|
5
5
|
* Extends #973; survives ceremony dial rapid/minimal (#3214).
|
|
6
6
|
*/
|
|
7
|
-
export { attachLiteralAcceptanceCommands, type CaptureLiteralAcceptanceResult, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, hasStructuredAcceptanceCommands, isProseDerivedRejection, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
|
|
7
|
+
export { attachLiteralAcceptanceCommands, type CaptureLiteralAcceptanceResult, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, hasStructuredAcceptanceCommands, INLINE_PROSE_MENTION_REASON, isInlineProseMention, isProseDerivedRejection, readNotAcceptanceCommands, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
|
|
8
8
|
export { appendLiteralAcceptanceAdvisory, type EvaluateLiteralAcceptanceOptions, evaluateLiteralAcceptanceFromPath, evaluateLiteralAcceptanceFromPlan, formatLiteralAcceptanceAdvisory, isLiteralAcceptanceRequiredAtCeremonyDepth, LITERAL_ACCEPTANCE_ADVISORY_MARKER, type ResolvedLiteralAcceptance, resolveLiteralAcceptanceCommands, resolveLiteralAcceptanceDetailed, stripLiteralAcceptanceAdvisory, } from "./evaluate.js";
|
|
9
9
|
export { defaultLiteralAcceptanceRunner, runLiteralAcceptanceCommand, runLiteralAcceptanceCommands, } from "./run.js";
|
|
10
10
|
export { type CommandSafetyResult, evaluateCommandSafety, evaluateNoopDenylist, evaluateStampAcceptanceSafety, isExecutableLiteralSource, isNoopRefusalReason, isVerbatimStatementSpan, NOOP_ACCEPTANCE_REMEDIATION, REJECTED_NOOP_OUTCOME, type RejectedNoopOutcome, type StampAcceptanceCommand, type StampAcceptanceSafetyInput, type StampAcceptanceSafetyResult, type StampSourceRung, } from "./safety.js";
|
|
11
|
-
export { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_METADATA_KEY, LITERAL_ACCEPTANCE_METADATA_KEY_CAMEL, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY, type LiteralAcceptanceCommand, type LiteralAcceptanceGateResult, type LiteralAcceptanceRunner, type LiteralAcceptanceRunResult, type LiteralAcceptanceSource, type RejectedLiteralCommand, } from "./types.js";
|
|
11
|
+
export { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_METADATA_KEY, LITERAL_ACCEPTANCE_METADATA_KEY_CAMEL, LITERAL_ACCEPTANCE_NOT_COMMANDS_METADATA_KEY, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY, type LiteralAcceptanceCommand, type LiteralAcceptanceGateResult, type LiteralAcceptanceRunner, type LiteralAcceptanceRunResult, type LiteralAcceptanceSource, type RejectedLiteralCommand, } from "./types.js";
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Capture exact stated shell commands at intake; run them verbatim before done.
|
|
5
5
|
* Extends #973; survives ceremony dial rapid/minimal (#3214).
|
|
6
6
|
*/
|
|
7
|
-
export { attachLiteralAcceptanceCommands, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, hasStructuredAcceptanceCommands, isProseDerivedRejection, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
|
|
7
|
+
export { attachLiteralAcceptanceCommands, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, hasStructuredAcceptanceCommands, INLINE_PROSE_MENTION_REASON, isInlineProseMention, isProseDerivedRejection, readNotAcceptanceCommands, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
|
|
8
8
|
export { appendLiteralAcceptanceAdvisory, evaluateLiteralAcceptanceFromPath, evaluateLiteralAcceptanceFromPlan, formatLiteralAcceptanceAdvisory, isLiteralAcceptanceRequiredAtCeremonyDepth, LITERAL_ACCEPTANCE_ADVISORY_MARKER, resolveLiteralAcceptanceCommands, resolveLiteralAcceptanceDetailed, stripLiteralAcceptanceAdvisory, } from "./evaluate.js";
|
|
9
9
|
export { defaultLiteralAcceptanceRunner, runLiteralAcceptanceCommand, runLiteralAcceptanceCommands, } from "./run.js";
|
|
10
10
|
export { evaluateCommandSafety, evaluateNoopDenylist, evaluateStampAcceptanceSafety, isExecutableLiteralSource, isNoopRefusalReason, isVerbatimStatementSpan, NOOP_ACCEPTANCE_REMEDIATION, REJECTED_NOOP_OUTCOME, } from "./safety.js";
|
|
11
|
-
export { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_METADATA_KEY, LITERAL_ACCEPTANCE_METADATA_KEY_CAMEL, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY, } from "./types.js";
|
|
11
|
+
export { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_METADATA_KEY, LITERAL_ACCEPTANCE_METADATA_KEY_CAMEL, LITERAL_ACCEPTANCE_NOT_COMMANDS_METADATA_KEY, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY, } from "./types.js";
|
|
12
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { spawnSync } from "node:child_process";
|
|
9
9
|
import { isAbsolute, resolve } from "node:path";
|
|
10
|
+
import { isInlineProseMention } from "./capture.js";
|
|
10
11
|
import { evaluateCommandSafety, isExecutableLiteralSource } from "./safety.js";
|
|
11
12
|
/** Default shell runner: exact command string via platform shell. */
|
|
12
13
|
export function defaultLiteralAcceptanceRunner(input) {
|
|
@@ -95,7 +96,9 @@ export function runLiteralAcceptanceCommands(commands, options) {
|
|
|
95
96
|
runs: [],
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
|
-
const untrusted = commands.filter((c) => c.source === "task_statement" &&
|
|
99
|
+
const untrusted = commands.filter((c) => c.source === "task_statement" &&
|
|
100
|
+
options.allowTaskStatement !== true &&
|
|
101
|
+
!isInlineProseMention(c));
|
|
99
102
|
const executable = commands.filter((c) => isExecutableLiteralSource(c.source) ||
|
|
100
103
|
(c.source === "task_statement" && options.allowTaskStatement === true));
|
|
101
104
|
// Fail closed: every capture-only stated command must have a matching agent-promoted
|
|
@@ -149,8 +152,11 @@ export function runLiteralAcceptanceCommands(commands, options) {
|
|
|
149
152
|
code: 1,
|
|
150
153
|
message: `Literal acceptance-command gate FAILED (#3267): ${unpromoted.length} stated command(s) ` +
|
|
151
154
|
`are capture-only (source=task_statement) and have no matching agent-promoted peer.\n` +
|
|
152
|
-
`
|
|
153
|
-
`
|
|
155
|
+
`If the command is this story's acceptance, promote the exact strings ` +
|
|
156
|
+
`(and cwd/expectedStdout/expectedExitCode when stated) into ` +
|
|
157
|
+
`plan.metadata.swarm.verify_commands (or plan item / explicit metadata), then re-run.\n` +
|
|
158
|
+
`If the capture is not an acceptance command, record the exact string in ` +
|
|
159
|
+
`plan.metadata.literal_acceptance_not_commands without promoting it (#3721).\n` +
|
|
154
160
|
`Note: an unrelated executable peer or a same-text peer with different context does not waive.\n` +
|
|
155
161
|
listed,
|
|
156
162
|
commands,
|
|
@@ -74,6 +74,12 @@ export interface LiteralAcceptanceGateResult {
|
|
|
74
74
|
}
|
|
75
75
|
/** Metadata key for operator-visible rejected command ledger (#3267). */
|
|
76
76
|
export declare const LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY: "literal_acceptance_rejected";
|
|
77
|
+
/**
|
|
78
|
+
* Metadata key: command strings the operator recorded as *not* acceptance
|
|
79
|
+
* commands (#3721). Disposition without promotion — listing a string here does
|
|
80
|
+
* not assert it is the story's verification.
|
|
81
|
+
*/
|
|
82
|
+
export declare const LITERAL_ACCEPTANCE_NOT_COMMANDS_METADATA_KEY: "literal_acceptance_not_commands";
|
|
77
83
|
/** Injectable shell runner for tests (default: spawnSync shell). */
|
|
78
84
|
export type LiteralAcceptanceRunner = (input: {
|
|
79
85
|
readonly command: string;
|
|
@@ -19,6 +19,12 @@ export const EXECUTABLE_LITERAL_SOURCES = [
|
|
|
19
19
|
];
|
|
20
20
|
/** Metadata key for operator-visible rejected command ledger (#3267). */
|
|
21
21
|
export const LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY = "literal_acceptance_rejected";
|
|
22
|
+
/**
|
|
23
|
+
* Metadata key: command strings the operator recorded as *not* acceptance
|
|
24
|
+
* commands (#3721). Disposition without promotion — listing a string here does
|
|
25
|
+
* not assert it is the story's verification.
|
|
26
|
+
*/
|
|
27
|
+
export const LITERAL_ACCEPTANCE_NOT_COMMANDS_METADATA_KEY = "literal_acceptance_not_commands";
|
|
22
28
|
/** Metadata key on plan.metadata for captured literal commands (#3267). */
|
|
23
29
|
export const LITERAL_ACCEPTANCE_METADATA_KEY = "literal_acceptance_commands";
|
|
24
30
|
/** Alternate camelCase key accepted on read. */
|
|
@@ -2,6 +2,19 @@ export declare const GATE_CLASSES: Set<string>;
|
|
|
2
2
|
export declare const GATE_TIERS: Set<string>;
|
|
3
3
|
export declare const GATE_MATCH_PREDICATES: Set<string>;
|
|
4
4
|
export declare const GATE_MATCH_STATES: Set<string>;
|
|
5
|
+
/** ADR-005 / #3434 Story 1 -- author-stamped marker vocabulary. */
|
|
6
|
+
export declare const DESIGN_CRITIQUE_GATE_ID = "design-critique";
|
|
7
|
+
/** List-visible mirror; this is what judgmentGates predicates match. */
|
|
8
|
+
export declare const DESIGN_CRITIQUE_MARKER_LABEL = "design-critique:mechanism-shaped";
|
|
9
|
+
/** Authoritative body-text field in the #1423 triage write-back comment. */
|
|
10
|
+
export declare const DESIGN_CRITIQUE_MARKER_FIELD = "mechanism-shaped: true";
|
|
11
|
+
/**
|
|
12
|
+
* Clearance line shape (ADR-005). Presence and shape only -- a non-empty
|
|
13
|
+
* because-clause is required; its semantic content is never evaluated.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DESIGN_CRITIQUE_CLEARANCE_SHAPE: RegExp;
|
|
16
|
+
/** True when `line` has clearance presence+shape. Never scores the reason text. */
|
|
17
|
+
export declare function designCritiqueClearanceShapeOk(line: string): boolean;
|
|
5
18
|
export interface JudgmentGate {
|
|
6
19
|
readonly gate_id: string;
|
|
7
20
|
readonly gate_class: string;
|
|
@@ -7,6 +7,21 @@ export const GATE_CLASSES = new Set(["mechanical", "declared"]);
|
|
|
7
7
|
export const GATE_TIERS = new Set(["auto", "review", "block"]);
|
|
8
8
|
export const GATE_MATCH_PREDICATES = new Set(["labels", "body-text", "paths", "state", "age-days"]);
|
|
9
9
|
export const GATE_MATCH_STATES = new Set(["open", "closed"]);
|
|
10
|
+
/** ADR-005 / #3434 Story 1 -- author-stamped marker vocabulary. */
|
|
11
|
+
export const DESIGN_CRITIQUE_GATE_ID = "design-critique";
|
|
12
|
+
/** List-visible mirror; this is what judgmentGates predicates match. */
|
|
13
|
+
export const DESIGN_CRITIQUE_MARKER_LABEL = "design-critique:mechanism-shaped";
|
|
14
|
+
/** Authoritative body-text field in the #1423 triage write-back comment. */
|
|
15
|
+
export const DESIGN_CRITIQUE_MARKER_FIELD = "mechanism-shaped: true";
|
|
16
|
+
/**
|
|
17
|
+
* Clearance line shape (ADR-005). Presence and shape only -- a non-empty
|
|
18
|
+
* because-clause is required; its semantic content is never evaluated.
|
|
19
|
+
*/
|
|
20
|
+
export const DESIGN_CRITIQUE_CLEARANCE_SHAPE = /^design-critique:\s*(warranted|not warranted),\s*because\s+\S/i;
|
|
21
|
+
/** True when `line` has clearance presence+shape. Never scores the reason text. */
|
|
22
|
+
export function designCritiqueClearanceShapeOk(line) {
|
|
23
|
+
return DESIGN_CRITIQUE_CLEARANCE_SHAPE.test(line.trim());
|
|
24
|
+
}
|
|
10
25
|
function validateStrList(value, prefix, key) {
|
|
11
26
|
if (!Array.isArray(value) || value.length === 0) {
|
|
12
27
|
return [`${prefix}.${key} must be a non-empty list of strings`];
|
|
@@ -12,6 +12,11 @@ export const SESSION_RELPATH = [".deft", "probe-session.json"];
|
|
|
12
12
|
export const STATE_INTERROGATE = "interrogate";
|
|
13
13
|
export const STATE_COMPLETE = "complete";
|
|
14
14
|
export const VALID_DECISION_STATUSES = new Set(["locked", "deferred", "risk-accepted"]);
|
|
15
|
+
/** Live CLI teach-string (#3556). The Python helper was deleted. */
|
|
16
|
+
const PROBE_SESSION_START = "`deft probe-session start --target <scope>`";
|
|
17
|
+
const PROBE_SESSION_RECORD = "`deft probe-session record ...`";
|
|
18
|
+
const PROBE_SESSION_COMPLETE = "`deft probe-session complete`";
|
|
19
|
+
const NO_SESSION_START = `No active probe session. Start one with ${PROBE_SESSION_START}.`;
|
|
15
20
|
export class ProbeHandoffBlockedError extends Error {
|
|
16
21
|
session;
|
|
17
22
|
constructor(message, session = null) {
|
|
@@ -249,7 +254,7 @@ export function startSession(projectRoot, options) {
|
|
|
249
254
|
export function recordDecision(projectRoot, options) {
|
|
250
255
|
const session = readSession(projectRoot);
|
|
251
256
|
if (session === null) {
|
|
252
|
-
throw new ProbeHandoffBlockedError(
|
|
257
|
+
throw new ProbeHandoffBlockedError(NO_SESSION_START);
|
|
253
258
|
}
|
|
254
259
|
if (session.state !== STATE_INTERROGATE) {
|
|
255
260
|
throw new ProbeHandoffBlockedError("Probe session is already complete; decisions cannot be appended.", session);
|
|
@@ -275,7 +280,7 @@ export function recordDecision(projectRoot, options) {
|
|
|
275
280
|
export function setCurrentBranch(projectRoot, branch) {
|
|
276
281
|
const session = readSession(projectRoot);
|
|
277
282
|
if (session === null) {
|
|
278
|
-
throw new ProbeHandoffBlockedError(
|
|
283
|
+
throw new ProbeHandoffBlockedError(NO_SESSION_START);
|
|
279
284
|
}
|
|
280
285
|
if (session.state !== STATE_INTERROGATE) {
|
|
281
286
|
throw new ProbeHandoffBlockedError("Probe session is already complete; current branch cannot change.", session);
|
|
@@ -287,7 +292,7 @@ export function setCurrentBranch(projectRoot, branch) {
|
|
|
287
292
|
export function markComplete(projectRoot, now) {
|
|
288
293
|
const session = readSession(projectRoot);
|
|
289
294
|
if (session === null) {
|
|
290
|
-
throw new ProbeHandoffBlockedError(
|
|
295
|
+
throw new ProbeHandoffBlockedError(NO_SESSION_START);
|
|
291
296
|
}
|
|
292
297
|
if (session.state === STATE_COMPLETE) {
|
|
293
298
|
return session;
|
|
@@ -307,7 +312,7 @@ function pythonRepr(value) {
|
|
|
307
312
|
function blockedMessage(session, action) {
|
|
308
313
|
if (session === null) {
|
|
309
314
|
return (`Probe handoff blocked for ${action}: no active probe session. ` +
|
|
310
|
-
|
|
315
|
+
`Start interrogation with ${PROBE_SESSION_START} ` +
|
|
311
316
|
"and finish with `... complete` only after transition criteria are met.");
|
|
312
317
|
}
|
|
313
318
|
return (`Probe handoff blocked for ${action}: session state is ` +
|
|
@@ -315,9 +320,9 @@ function blockedMessage(session, action) {
|
|
|
315
320
|
`currentBranch=${pythonRepr(session.current_branch)}, ` +
|
|
316
321
|
`resolvedDecisions=${session.resolved_decisions.length}). ` +
|
|
317
322
|
"Continue interrogation until transition criteria are met, record decisions " +
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
"or updating completedStrategies.probe in plan.
|
|
323
|
+
`with ${PROBE_SESSION_RECORD}, then run ` +
|
|
324
|
+
`${PROBE_SESSION_COMPLETE} before writing artifacts ` +
|
|
325
|
+
"or updating completedStrategies.probe in plan.xbrief.json.");
|
|
321
326
|
}
|
|
322
327
|
export function requireHandoffAllowed(projectRoot, action) {
|
|
323
328
|
const session = readSession(projectRoot);
|
|
@@ -330,7 +335,7 @@ export function guardProbeArtifact(projectRoot, artifactPath) {
|
|
|
330
335
|
return requireHandoffAllowed(projectRoot, `probe artifact write (${artifactPath})`);
|
|
331
336
|
}
|
|
332
337
|
export function guardPlanProbeRegistration(projectRoot) {
|
|
333
|
-
return requireHandoffAllowed(projectRoot, "completedStrategies.probe registration in plan.
|
|
338
|
+
return requireHandoffAllowed(projectRoot, "completedStrategies.probe registration in plan.xbrief.json");
|
|
334
339
|
}
|
|
335
340
|
export function sessionSummary(session) {
|
|
336
341
|
return {
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Risk-tiered judgment-gate engine (#1419 Slice 3). Port of scripts/verify_judgment_gates.py.
|
|
3
3
|
*/
|
|
4
4
|
import { type JudgmentGatesPolicy } from "./judgment-policy.js";
|
|
5
|
+
/** Thrown when a design-critique clearance reason fails presence/shape (never content). */
|
|
6
|
+
export declare class JudgmentClearanceShapeError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
5
9
|
/** Display/back-compat constant; resolution flows through resolveAuditDir (#2109). */
|
|
6
10
|
export declare const AUDIT_DIR_REL = "vbrief/.audit";
|
|
7
11
|
export declare const CLEARANCE_LOG_NAME = "judgment-gate-clearances.jsonl";
|
|
@@ -7,8 +7,15 @@ import { appendFileSync, existsSync, lstatSync, mkdirSync, readFileSync, statSyn
|
|
|
7
7
|
import { join, resolve } from "node:path";
|
|
8
8
|
import { assertProjectionContained, assertWriteTargetSafe, ProjectionContainmentError, } from "../fs/projection-containment.js";
|
|
9
9
|
import { resolveAuditDir } from "../layout/resolve.js";
|
|
10
|
-
import { resolveJudgmentGates } from "./judgment-policy.js";
|
|
10
|
+
import { DESIGN_CRITIQUE_GATE_ID, designCritiqueClearanceShapeOk, resolveJudgmentGates, } from "./judgment-policy.js";
|
|
11
11
|
import { matchAny } from "./pathspec.js";
|
|
12
|
+
/** Thrown when a design-critique clearance reason fails presence/shape (never content). */
|
|
13
|
+
export class JudgmentClearanceShapeError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "JudgmentClearanceShapeError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
12
19
|
/** Display/back-compat constant; resolution flows through resolveAuditDir (#2109). */
|
|
13
20
|
export const AUDIT_DIR_REL = "vbrief/.audit";
|
|
14
21
|
export const CLEARANCE_LOG_NAME = "judgment-gate-clearances.jsonl";
|
|
@@ -163,6 +170,12 @@ export function readClearances(projectRoot, logPath) {
|
|
|
163
170
|
return out;
|
|
164
171
|
}
|
|
165
172
|
export function recordClearance(projectRoot, options) {
|
|
173
|
+
if (options.gate_id === DESIGN_CRITIQUE_GATE_ID &&
|
|
174
|
+
!designCritiqueClearanceShapeOk(options.reason ?? "")) {
|
|
175
|
+
throw new JudgmentClearanceShapeError("design-critique clearance reason must match shape " +
|
|
176
|
+
"'design-critique: warranted | not warranted, because ...' " +
|
|
177
|
+
"(presence and shape only; the because-clause is not scored)");
|
|
178
|
+
}
|
|
166
179
|
const path = options.log_path ?? clearanceLogPath(projectRoot);
|
|
167
180
|
const auditDir = resolveAuditDir(projectRoot);
|
|
168
181
|
assertProjectionContained(projectRoot, auditDir);
|
|
@@ -202,6 +215,15 @@ export function fingerprintScope(evidence) {
|
|
|
202
215
|
const payload = JSON.stringify(sorted);
|
|
203
216
|
return createHash("sha256").update(payload, "utf8").digest("hex");
|
|
204
217
|
}
|
|
218
|
+
function acceptClearanceShape(gateId, clearance) {
|
|
219
|
+
if (clearance === null) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
if (gateId !== DESIGN_CRITIQUE_GATE_ID) {
|
|
223
|
+
return clearance;
|
|
224
|
+
}
|
|
225
|
+
return designCritiqueClearanceShapeOk(String(clearance.reason ?? "")) ? clearance : null;
|
|
226
|
+
}
|
|
205
227
|
function lookupClearance(clearances, gateId, scope) {
|
|
206
228
|
let valid = null;
|
|
207
229
|
let stale = null;
|
|
@@ -383,7 +405,8 @@ export function buildReport(projectRoot, candidate, options = {}) {
|
|
|
383
405
|
continue;
|
|
384
406
|
}
|
|
385
407
|
const scope = fingerprintScope(evidence);
|
|
386
|
-
const [
|
|
408
|
+
const [validRaw, stale] = lookupClearance(records, String(gate.id), scope);
|
|
409
|
+
const valid = acceptClearanceShape(String(gate.id), validRaw);
|
|
387
410
|
outcomes.push({
|
|
388
411
|
gate_id: String(gate.id),
|
|
389
412
|
gate_class: String(gate.class),
|
|
@@ -605,15 +628,24 @@ function clearMain(argv) {
|
|
|
605
628
|
if (args.updatedAt !== null)
|
|
606
629
|
evidence["age-days"] = args.updatedAt;
|
|
607
630
|
const scope = fingerprintScope(evidence);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
631
|
+
try {
|
|
632
|
+
const entry = recordClearance(projectRoot, {
|
|
633
|
+
gate_id: args.gateId,
|
|
634
|
+
cleared_scope: scope,
|
|
635
|
+
reviewers: args.reviewers,
|
|
636
|
+
actor: args.actor,
|
|
637
|
+
reason: args.reason,
|
|
638
|
+
});
|
|
639
|
+
process.stdout.write(`recorded clearance ${String(entry.clearance_id)} for gate ${JSON.stringify(args.gateId)} (cleared_scope=${scope.slice(0, 12)}...)\n`);
|
|
640
|
+
return 0;
|
|
641
|
+
}
|
|
642
|
+
catch (err) {
|
|
643
|
+
if (err instanceof JudgmentClearanceShapeError) {
|
|
644
|
+
process.stderr.write(`${err.message}\n`);
|
|
645
|
+
return 1;
|
|
646
|
+
}
|
|
647
|
+
throw err;
|
|
648
|
+
}
|
|
617
649
|
}
|
|
618
650
|
function parseEvalArgs(argv) {
|
|
619
651
|
const parsed = {
|
|
@@ -23,7 +23,7 @@ import { RunSummaryEmitter } from "../run-summary/emit.js";
|
|
|
23
23
|
import { atomicWriteProjectDefinition, projectDefinitionMutationLock, } from "../vbrief-build/project-definition-io.js";
|
|
24
24
|
import { migrateLegacyPolicyKey, PLAN_POLICY_KEY, readPlanPolicy } from "./plan-extensions.js";
|
|
25
25
|
import { policyColonInvocation } from "./policy-invocation.js";
|
|
26
|
-
import { appendAuditLog, loadProjectDefinition, projectDefinitionPath } from "./resolve.js";
|
|
26
|
+
import { appendAuditLog, loadProjectDefinition, POLICY_AUDIT_NOOP_STDOUT, projectDefinitionPath, } from "./resolve.js";
|
|
27
27
|
/** Canonical dotted policy field name. */
|
|
28
28
|
export const FIELD_CEREMONY_DIAL = "plan.policy.ceremonyDial";
|
|
29
29
|
/** Short alias for `policy:show --field=ceremonyDial`. */
|
|
@@ -527,7 +527,7 @@ export function setCeremonyDial(projectRoot, options) {
|
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
529
|
const plan = data.plan;
|
|
530
|
-
migrateLegacyPolicyKey(plan);
|
|
530
|
+
const legacyKeyMigrated = migrateLegacyPolicyKey(plan);
|
|
531
531
|
const existingPolicy = plan[PLAN_POLICY_KEY];
|
|
532
532
|
if (typeof existingPolicy !== "object" ||
|
|
533
533
|
existingPolicy === null ||
|
|
@@ -564,7 +564,9 @@ export function setCeremonyDial(projectRoot, options) {
|
|
|
564
564
|
override: nextOverride,
|
|
565
565
|
};
|
|
566
566
|
const prevParsed = parseConfig(previous).config;
|
|
567
|
-
const changedFlag = prevParsed.enabled !== nextBlock.enabled ||
|
|
567
|
+
const changedFlag = prevParsed.enabled !== nextBlock.enabled ||
|
|
568
|
+
prevParsed.override !== nextBlock.override ||
|
|
569
|
+
legacyKeyMigrated;
|
|
568
570
|
policyBlock.ceremonyDial = nextBlock;
|
|
569
571
|
if (changedFlag) {
|
|
570
572
|
atomicWriteProjectDefinition(path, data);
|
|
@@ -580,15 +582,13 @@ export function setCeremonyDial(projectRoot, options) {
|
|
|
580
582
|
if (note) {
|
|
581
583
|
parts.push(`note=${note.replace(/\n/g, " ").replace(/\r/g, " ")}`);
|
|
582
584
|
}
|
|
583
|
-
appendAuditLog(projectRoot, parts.join(" "));
|
|
585
|
+
appendAuditLog(projectRoot, parts.join(" "), changedFlag);
|
|
584
586
|
return { changed: changedFlag };
|
|
585
587
|
});
|
|
586
588
|
const resolved = resolveCeremonyDial(projectRoot);
|
|
587
589
|
const lines = [
|
|
588
590
|
`\u2713 ${FIELD_CEREMONY_DIAL} updated.`,
|
|
589
|
-
changed
|
|
590
|
-
? " audit: meta/policy-changes.log updated."
|
|
591
|
-
: " no-op: value already matched (audit entry still appended for trail).",
|
|
591
|
+
changed ? " audit: meta/policy-changes.log updated." : POLICY_AUDIT_NOOP_STDOUT,
|
|
592
592
|
formatCeremonyDialStatusLine(resolved),
|
|
593
593
|
];
|
|
594
594
|
return { exitCode: 0, stdout: `${lines.join("\n")}\n`, changed };
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { HookHost } from "../hooks/dispatcher.js";
|
|
2
|
+
export type { HookHost };
|
|
2
3
|
export declare const FIELD_HOST_HOOKS = "plan.policy.hostHooks";
|
|
3
4
|
export declare const FIELD_HOST_HOOKS_CLI_ALIAS = "hostHooks";
|
|
5
|
+
export declare const DISABLE_HOST_HOOKS_SUBCOMMAND = "disable-host-hooks";
|
|
6
|
+
/** Confirm-gated disable verb for unused-host recovery copy (#3571). CLI form: no go-task `--`. */
|
|
7
|
+
export declare function disableHostHooksInvocation(trailing?: string): string;
|
|
8
|
+
export declare const HOST_HOOKS_DISABLE_CAPABILITY_COST_DISCLOSURE: string;
|
|
9
|
+
export declare const UNUSED_HOST_HOOKS_RECOVERY: string;
|
|
4
10
|
/** Per-host Directive hook deposit toggles (#2752). */
|
|
5
11
|
export type HostHooksPolicy = Record<HookHost, boolean>;
|
|
6
12
|
export declare const DEFAULT_HOST_HOOKS_POLICY: HostHooksPolicy;
|
|
@@ -18,4 +24,18 @@ export declare function isHostHookDepositEnabled(host: HookHost, policy?: HostHo
|
|
|
18
24
|
export declare function inspectHostHooks(data: Record<string, unknown> | null): HostHooksPolicyField;
|
|
19
25
|
/** Resolve host hook deposit policy from PROJECT-DEFINITION on disk. */
|
|
20
26
|
export declare function loadHostHooksPolicyFromProject(projectRoot: string): HostHooksPolicy;
|
|
27
|
+
export declare function parseHookHost(value: string | undefined): HookHost | null;
|
|
28
|
+
export interface DisableHostHooksOptions {
|
|
29
|
+
readonly host: HookHost;
|
|
30
|
+
readonly confirm: boolean;
|
|
31
|
+
readonly actor?: string;
|
|
32
|
+
readonly note?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface DisableHostHooksResult {
|
|
35
|
+
readonly exitCode: 0 | 1 | 2;
|
|
36
|
+
readonly stdout: string;
|
|
37
|
+
readonly changed: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Persist `hostHooks.<host>=false` after capability-cost disclosure (#3571). */
|
|
40
|
+
export declare function disableHostHooks(projectRoot: string, options: DisableHostHooksOptions): DisableHostHooksResult;
|
|
21
41
|
//# sourceMappingURL=host-hooks.d.ts.map
|