@deftai/directive-core 0.107.0 → 0.109.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/architecture/sor-preflight.js +2 -0
- package/dist/cache/operations.js +1 -1
- package/dist/check/cached-orchestrator.js +28 -3
- package/dist/check/gate-lists.d.ts +14 -0
- package/dist/check/gate-lists.js +26 -3
- package/dist/check/named-cause.js +18 -3
- package/dist/check/session-completed-ac.d.ts +1 -1
- package/dist/check/session-completed-ac.js +1 -1
- package/dist/codebase/provider.js +7 -1
- package/dist/consumer-check-contract/evaluate.d.ts +47 -0
- package/dist/consumer-check-contract/evaluate.js +181 -15
- package/dist/delivery-attempt/evaluate.d.ts +9 -1
- package/dist/delivery-attempt/evaluate.js +69 -0
- package/dist/delivery-attempt/handoff.js +1 -1
- package/dist/delivery-attempt/index.d.ts +1 -1
- package/dist/delivery-attempt/index.js +1 -1
- package/dist/deposit/live-procedure-exclusions.d.ts +18 -0
- package/dist/deposit/live-procedure-exclusions.js +110 -0
- package/dist/deposit/live-procedure-targets.d.ts +45 -0
- package/dist/deposit/live-procedure-targets.js +274 -0
- package/dist/deposit/python-free.d.ts +6 -0
- package/dist/deposit/python-free.js +15 -0
- package/dist/deposit/rewrite-deposit-links.d.ts +42 -0
- package/dist/deposit/rewrite-deposit-links.js +148 -0
- package/dist/deposit/run-stage-content-pack.d.ts +2 -0
- package/dist/deposit/run-stage-content-pack.js +3 -0
- package/dist/deposit/stage-content-pack.d.ts +17 -0
- package/dist/deposit/stage-content-pack.js +91 -0
- package/dist/design-critique/citation-grammar.d.ts +60 -0
- package/dist/design-critique/citation-grammar.js +303 -0
- package/dist/design-critique/completed-arc-record.d.ts +62 -0
- package/dist/design-critique/completed-arc-record.js +277 -0
- package/dist/freshness/bind.d.ts +32 -3
- package/dist/freshness/bind.js +58 -12
- package/dist/hooks/classify/host-session-identity.d.ts +89 -0
- package/dist/hooks/classify/host-session-identity.js +467 -0
- package/dist/hooks/classify/index.d.ts +3 -2
- package/dist/hooks/classify/index.js +3 -2
- package/dist/hooks/classify/paths.d.ts +9 -0
- package/dist/hooks/classify/paths.js +39 -0
- package/dist/hooks/classify/stdin.d.ts +5 -0
- package/dist/hooks/classify/stdin.js +94 -1
- package/dist/hooks/dest-form.d.ts +20 -1
- package/dist/hooks/dest-form.js +158 -21
- package/dist/hooks/dispatcher.d.ts +58 -3
- package/dist/hooks/dispatcher.js +762 -73
- package/dist/hooks/fixtures/cases.d.ts +22 -2
- package/dist/hooks/fixtures/cases.js +228 -0
- package/dist/hooks/git-destructive-log.d.ts +32 -0
- package/dist/hooks/git-destructive-log.js +46 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/scope.js +3 -1
- package/dist/hooks/shell-write-targets.d.ts +10 -0
- package/dist/hooks/shell-write-targets.js +274 -0
- package/dist/hooks/tools.d.ts +20 -2
- package/dist/hooks/tools.js +30 -1
- package/dist/init-deposit/agent-hooks.d.ts +2 -1
- package/dist/init-deposit/agent-hooks.js +8 -1
- package/dist/init-deposit/gitignore.d.ts +7 -0
- package/dist/init-deposit/gitignore.js +24 -0
- package/dist/init-deposit/hook-runtime-travel.d.ts +77 -0
- package/dist/init-deposit/hook-runtime-travel.js +269 -0
- package/dist/init-deposit/init-deposit.js +3 -0
- package/dist/init-deposit/refresh.js +7 -0
- package/dist/init-deposit/runtime-writers.d.ts +14 -0
- package/dist/init-deposit/runtime-writers.js +33 -0
- package/dist/intake/clause-derivation.js +9 -3
- package/dist/intake/issue-ingest.d.ts +6 -1
- package/dist/intake/issue-ingest.js +83 -4
- package/dist/intake/platform-capabilities.d.ts +9 -2
- package/dist/intake/platform-capabilities.js +38 -9
- package/dist/intake/reconcile-issues.js +13 -13
- package/dist/lifecycle/brief-envelope.d.ts +25 -0
- package/dist/lifecycle/brief-envelope.js +42 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/literal-acceptance/evaluate.js +14 -5
- package/dist/literal-acceptance/index.d.ts +1 -1
- package/dist/literal-acceptance/index.js +1 -1
- package/dist/literal-acceptance/run.d.ts +2 -0
- package/dist/literal-acceptance/run.js +19 -1
- package/dist/orphan-active/candidate-scope.d.ts +53 -0
- package/dist/orphan-active/candidate-scope.js +157 -0
- package/dist/orphan-active/evaluate.d.ts +52 -0
- package/dist/orphan-active/evaluate.js +250 -128
- package/dist/orphan-active/index.d.ts +2 -0
- package/dist/orphan-active/index.js +2 -0
- package/dist/orphan-active/issue-state.d.ts +121 -0
- package/dist/orphan-active/issue-state.js +278 -0
- package/dist/platform/cursor-managed-runtime.d.ts +95 -0
- package/dist/platform/cursor-managed-runtime.js +241 -0
- package/dist/platform/index.d.ts +1 -0
- package/dist/platform/index.js +1 -0
- package/dist/platform/platform-capabilities.d.ts +23 -1
- package/dist/platform/platform-capabilities.js +55 -15
- package/dist/policy/ceremony-dial.js +5 -9
- package/dist/policy/host-hooks.js +4 -9
- package/dist/policy/merge-approval-head.js +7 -6
- package/dist/policy/org-force-on-migration.js +5 -10
- package/dist/policy/plan-extensions.d.ts +14 -2
- package/dist/policy/plan-extensions.js +24 -3
- package/dist/policy/product-signal.js +5 -10
- package/dist/policy/require-human-merge.js +5 -9
- package/dist/policy/resolve.js +77 -16
- package/dist/policy/value-feedback.js +9 -18
- package/dist/pr-closeout-attestable/evaluate.d.ts +80 -0
- package/dist/pr-closeout-attestable/evaluate.js +306 -0
- package/dist/pr-closeout-attestable/index.d.ts +2 -0
- package/dist/pr-closeout-attestable/index.js +2 -0
- package/dist/pr-closing-keywords/gh.js +32 -9
- package/dist/pr-closing-keywords/main.d.ts +1 -0
- package/dist/pr-closing-keywords/main.js +68 -3
- package/dist/pr-closing-keywords/types.d.ts +2 -0
- package/dist/pr-merge-readiness/gh.js +32 -9
- package/dist/pr-protected-issues/gh.d.ts +6 -2
- package/dist/pr-protected-issues/gh.js +42 -11
- package/dist/pr-wait-mergeable/cascade.d.ts +9 -1
- package/dist/pr-wait-mergeable/cascade.js +21 -1
- package/dist/pr-wait-mergeable/types.d.ts +2 -0
- package/dist/pr-wait-mergeable/wrappers.d.ts +6 -0
- package/dist/pr-wait-mergeable/wrappers.js +14 -3
- package/dist/preflight/evaluate.d.ts +15 -0
- package/dist/preflight/evaluate.js +29 -3
- package/dist/product-first-done-gate/acceptance-resolver.d.ts +14 -2
- package/dist/product-first-done-gate/acceptance-resolver.js +13 -2
- package/dist/product-first-done-gate/evaluate.js +23 -9
- package/dist/product-first-done-gate/types.js +2 -0
- package/dist/release/cli-drift-report.d.ts +68 -0
- package/dist/release/cli-drift-report.js +189 -0
- package/dist/release/consumer-hard-stops.d.ts +48 -0
- package/dist/release/consumer-hard-stops.js +140 -0
- package/dist/release/consumer-readiness-disclosure.d.ts +18 -0
- package/dist/release/consumer-readiness-disclosure.js +51 -0
- package/dist/release/index.d.ts +3 -0
- package/dist/release/index.js +3 -0
- package/dist/release/issue-state-fetch.d.ts +5 -3
- package/dist/release/issue-state-fetch.js +86 -21
- package/dist/release/native-steps.js +1 -0
- package/dist/release/pipeline.js +74 -0
- package/dist/release/run-consumer-readiness.d.ts +15 -0
- package/dist/release/run-consumer-readiness.js +24 -0
- package/dist/release/types.d.ts +20 -0
- package/dist/render/constants.d.ts +4 -0
- package/dist/render/constants.js +11 -8
- package/dist/render/export-spec.js +31 -5
- package/dist/render/index.d.ts +1 -1
- package/dist/render/index.js +1 -1
- package/dist/render/prd-render.d.ts +4 -1
- package/dist/render/prd-render.js +82 -23
- package/dist/render/project-render.js +14 -7
- package/dist/render/scope-outlook.d.ts +2 -0
- package/dist/render/scope-outlook.js +3 -0
- package/dist/render/spec-render.js +2 -2
- package/dist/resolution/package-manager.d.ts +33 -4
- package/dist/resolution/package-manager.js +210 -9
- package/dist/review-monitor/constants.d.ts +7 -0
- package/dist/review-monitor/constants.js +7 -0
- package/dist/review-monitor/github-lease.d.ts +98 -1
- package/dist/review-monitor/github-lease.js +186 -4
- package/dist/review-monitor/lease-comment.d.ts +36 -0
- package/dist/review-monitor/lease-comment.js +103 -2
- package/dist/run-summary/types.d.ts +2 -2
- package/dist/scm/build-command.d.ts +2 -2
- package/dist/scm/build-command.js +2 -2
- package/dist/scm/call-shape.d.ts +25 -0
- package/dist/scm/call-shape.js +59 -0
- package/dist/scm/call.d.ts +7 -4
- package/dist/scm/call.js +48 -9
- package/dist/scm/design-critique-chip.d.ts +1 -0
- package/dist/scm/design-critique-chip.js +22 -6
- package/dist/scm/gh-rest.d.ts +34 -13
- package/dist/scm/gh-rest.js +168 -15
- package/dist/scm/index.d.ts +2 -0
- package/dist/scm/index.js +2 -0
- package/dist/scm/readiness.d.ts +2 -0
- package/dist/scm/readiness.js +28 -4
- package/dist/scm/spawn-status.d.ts +33 -0
- package/dist/scm/spawn-status.js +53 -0
- package/dist/scope/acceptance-evidence.d.ts +1 -1
- package/dist/scope/project-definition-sync.js +14 -7
- package/dist/scope/transition.js +4 -14
- package/dist/session/ac-pass-banking.d.ts +2 -2
- package/dist/session/ac-pass-banking.js +2 -2
- package/dist/session/git.d.ts +24 -0
- package/dist/session/git.js +138 -2
- package/dist/session/host-session-owner.d.ts +53 -0
- package/dist/session/host-session-owner.js +89 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.js +1 -0
- package/dist/session/occupancy.d.ts +259 -13
- package/dist/session/occupancy.js +877 -33
- package/dist/session/ritual-sentinel.d.ts +5 -0
- package/dist/session/ritual-sentinel.js +5 -0
- package/dist/session/session-ready.d.ts +5 -1
- package/dist/session/session-ready.js +98 -8
- package/dist/session/session-start.d.ts +5 -1
- package/dist/session/session-start.js +32 -17
- package/dist/session/toolchain-preflight.d.ts +13 -3
- package/dist/session/toolchain-preflight.js +93 -18
- package/dist/session/verify-ac-session-cache.d.ts +2 -2
- package/dist/session/verify-ac-session-cache.js +2 -2
- package/dist/session/verify-session-ritual.d.ts +11 -0
- package/dist/session/verify-session-ritual.js +60 -15
- package/dist/slice/constants.d.ts +1 -1
- package/dist/spec-authority/constants.d.ts +10 -2
- package/dist/spec-authority/constants.js +53 -8
- package/dist/spec-authority/resolver.d.ts +3 -0
- package/dist/spec-authority/resolver.js +55 -7
- package/dist/subprocess/max-buffer.d.ts +14 -0
- package/dist/subprocess/max-buffer.js +15 -0
- package/dist/swarm/complete-cohort.d.ts +2 -0
- package/dist/swarm/complete-cohort.js +21 -13
- package/dist/swarm/index.d.ts +1 -0
- package/dist/swarm/index.js +1 -0
- package/dist/swarm/launch-cli.js +53 -33
- package/dist/swarm/launch.d.ts +8 -0
- package/dist/swarm/launch.js +63 -43
- package/dist/swarm/pre-dispatch-cli.js +2 -1
- package/dist/swarm/pre-dispatch.js +10 -1
- package/dist/swarm/subagent-status-dir.d.ts +27 -0
- package/dist/swarm/subagent-status-dir.js +42 -0
- package/dist/swarm/worktrees.d.ts +17 -3
- package/dist/swarm/worktrees.js +48 -4
- package/dist/triage/evaluate/worktrees.js +153 -6
- package/dist/triage/scope/mutations-core.d.ts +2 -6
- package/dist/triage/scope/mutations-core.js +23 -55
- package/dist/triage/scope-drift/add-ignore.js +5 -39
- package/dist/triage/subscribe/index.d.ts +2 -6
- package/dist/triage/subscribe/index.js +15 -65
- package/dist/triage/welcome/writers.js +15 -74
- package/dist/umbrella-current-shape/index.d.ts +51 -3
- package/dist/umbrella-current-shape/index.js +106 -18
- package/dist/validate-content/deposit-required.d.ts +39 -0
- package/dist/validate-content/deposit-required.js +147 -0
- package/dist/validate-content/index.d.ts +1 -0
- package/dist/validate-content/index.js +1 -0
- package/dist/validate-content/validate-links.d.ts +2 -3
- package/dist/validate-content/validate-links.js +29 -2
- package/dist/vbrief-activate/activate.d.ts +7 -2
- package/dist/vbrief-activate/activate.js +26 -13
- package/dist/vbrief-build/index.d.ts +2 -1
- package/dist/vbrief-build/index.js +2 -1
- package/dist/vbrief-build/parity-scenarios.js +5 -5
- package/dist/vbrief-build/project-definition-io.d.ts +63 -3
- package/dist/vbrief-build/project-definition-io.js +357 -31
- package/dist/vbrief-build/project-definition-mutation.d.ts +32 -0
- package/dist/vbrief-build/project-definition-mutation.js +43 -0
- package/dist/vbrief-validate/conformance.d.ts +1 -0
- package/dist/vbrief-validate/conformance.js +85 -8
- package/dist/vbrief-validate/main.js +2 -0
- package/dist/vbrief-validate/precutover.js +5 -10
- package/dist/verify-ac/clauses.d.ts +62 -2
- package/dist/verify-ac/clauses.js +183 -111
- package/dist/verify-ac/evaluate.d.ts +9 -0
- package/dist/verify-ac/evaluate.js +32 -9
- package/dist/verify-ac/index.d.ts +1 -1
- package/dist/verify-ac/index.js +1 -1
- package/dist/verify-env/node-runtime.d.ts +8 -4
- package/dist/verify-env/node-runtime.js +9 -6
- package/dist/verify-env/toolchain-check.d.ts +35 -3
- package/dist/verify-env/toolchain-check.js +155 -36
- package/dist/verify-source/deposit-closure.d.ts +23 -0
- package/dist/verify-source/deposit-closure.js +162 -0
- package/dist/verify-source/index.d.ts +2 -0
- package/dist/verify-source/index.js +2 -0
- package/dist/verify-source/project-definition-mutation-boundary.d.ts +104 -0
- package/dist/verify-source/project-definition-mutation-boundary.js +326 -0
- package/dist/verify-source/semantic-single-source.d.ts +36 -0
- package/dist/verify-source/semantic-single-source.js +349 -0
- package/package.json +7 -3
|
@@ -16,6 +16,7 @@ import { spawnSync } from "node:child_process";
|
|
|
16
16
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
17
17
|
import { basename, extname, join, resolve } from "node:path";
|
|
18
18
|
import { hasArtifactSuffix, LIFECYCLE_DIR_NAMES } from "../layout/resolve.js";
|
|
19
|
+
import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
20
21
|
// Classification constants
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
@@ -776,6 +777,7 @@ function gitDiff(projectRoot, baseRef) {
|
|
|
776
777
|
cwd: resolve(projectRoot),
|
|
777
778
|
encoding: "utf8",
|
|
778
779
|
timeout: 30_000,
|
|
780
|
+
maxBuffer: SUBPROCESS_MAX_BUFFER,
|
|
779
781
|
});
|
|
780
782
|
if (result.error) {
|
|
781
783
|
return [
|
package/dist/cache/operations.js
CHANGED
|
@@ -107,7 +107,7 @@ export function cachePut(source, key, raw, options = {}) {
|
|
|
107
107
|
const rawSize = Buffer.byteLength(rawText, "utf8");
|
|
108
108
|
// #1870 Greptile P2: account for current-shape sidecar bytes in cap + meta
|
|
109
109
|
// so usage does not underreport by the cumulative sidecar size.
|
|
110
|
-
const plannedSidecar = buildCurrentShapeSidecar(raw);
|
|
110
|
+
const plannedSidecar = buildCurrentShapeSidecar(raw).sidecar;
|
|
111
111
|
const plannedSidecarText = plannedSidecar !== null
|
|
112
112
|
? `${pythonJsonDump({
|
|
113
113
|
...plannedSidecar,
|
|
@@ -6,6 +6,7 @@ import { readCorePackageVersion } from "../engine-version.js";
|
|
|
6
6
|
import { applyProductFirstGateMode, EMPTY_AC_CAUSE, EMPTY_AC_REMEDY, isHygieneGate, isProductAcGate, isSoftEmptyAcText, resolveProductFirstCheckMode, } from "../product-first-done-gate/index.js";
|
|
7
7
|
import { RunSummaryEmitter } from "../run-summary/emit.js";
|
|
8
8
|
import { runToolchainPreflight, SKIP_ALL_GATES, } from "../session/toolchain-preflight.js";
|
|
9
|
+
import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
9
10
|
import { checkGateCliArgv, cliSpawnPlan, resolveGateDispatch, resolveGlobalCliBin, } from "./cli-native-gates.js";
|
|
10
11
|
import { evaluateConsumerGateIntegrity, formatConsumerGateIntegrityFailure, } from "./consumer-gate-integrity.js";
|
|
11
12
|
import { resolveCheckTarget } from "./context.js";
|
|
@@ -17,6 +18,7 @@ function captureSpawn(taskBin, args, opts) {
|
|
|
17
18
|
cwd: opts.cwd,
|
|
18
19
|
encoding: "utf8",
|
|
19
20
|
env: opts.env ?? process.env,
|
|
21
|
+
maxBuffer: SUBPROCESS_MAX_BUFFER,
|
|
20
22
|
});
|
|
21
23
|
if (result.error !== undefined) {
|
|
22
24
|
return {
|
|
@@ -40,6 +42,27 @@ function writeLines(lines, stream = "stderr") {
|
|
|
40
42
|
write(`${line}\n`);
|
|
41
43
|
}
|
|
42
44
|
}
|
|
45
|
+
function firstImpactingMissingFinding(preflight) {
|
|
46
|
+
const missing = preflight?.findings.filter((finding) => !finding.present) ?? [];
|
|
47
|
+
const impacting = missing.filter((finding) => finding.impact !== "none");
|
|
48
|
+
const priority = [
|
|
49
|
+
"node",
|
|
50
|
+
"task",
|
|
51
|
+
"cli_dist",
|
|
52
|
+
"package_manager",
|
|
53
|
+
preflight?.packageManager,
|
|
54
|
+
"npm",
|
|
55
|
+
"pnpm",
|
|
56
|
+
];
|
|
57
|
+
for (const tool of priority) {
|
|
58
|
+
if (tool === null || tool === undefined)
|
|
59
|
+
continue;
|
|
60
|
+
const finding = impacting.find((candidate) => candidate.tool === tool);
|
|
61
|
+
if (finding !== undefined)
|
|
62
|
+
return finding;
|
|
63
|
+
}
|
|
64
|
+
return impacting[0] ?? missing[0];
|
|
65
|
+
}
|
|
43
66
|
/**
|
|
44
67
|
* Run check gates sequentially with content-hash caching (#1713).
|
|
45
68
|
* Falls back to fail-open execution for undeclared / non-cacheable gates.
|
|
@@ -135,6 +158,7 @@ export function dispatchCachedTaskCheck(frameworkRoot, projectRoot, options = {}
|
|
|
135
158
|
composedGates: gates,
|
|
136
159
|
consumerDeposit: target === "check:consumer",
|
|
137
160
|
which,
|
|
161
|
+
env: options.env,
|
|
138
162
|
})
|
|
139
163
|
: options.preflight;
|
|
140
164
|
const taskPresent = preflight === null || !preflight.findings.some((f) => f.tool === "task" && !f.present);
|
|
@@ -165,8 +189,9 @@ export function dispatchCachedTaskCheck(frameworkRoot, projectRoot, options = {}
|
|
|
165
189
|
if (allSkipped) {
|
|
166
190
|
const skipped = gates.map((g) => {
|
|
167
191
|
const id = checkGateId(g);
|
|
168
|
-
const
|
|
169
|
-
const
|
|
192
|
+
const missing = firstImpactingMissingFinding(preflight);
|
|
193
|
+
const cause = missing?.cause ?? "toolchain preflight degraded";
|
|
194
|
+
const remedy = missing?.remedy ?? remedyForGate(id, cause);
|
|
170
195
|
gateOutcomes.push({ id, status: "skipped", cause, remedy });
|
|
171
196
|
return { id, cause, remedy };
|
|
172
197
|
});
|
|
@@ -183,7 +208,7 @@ export function dispatchCachedTaskCheck(frameworkRoot, projectRoot, options = {}
|
|
|
183
208
|
const gateId = checkGateId(gateSpec);
|
|
184
209
|
// #3282: skip gates that require missing tools (e.g. pnpm-only suite).
|
|
185
210
|
if (skipSet.has(gateId)) {
|
|
186
|
-
const missing = preflight
|
|
211
|
+
const missing = firstImpactingMissingFinding(preflight);
|
|
187
212
|
const cause = missing?.cause ?? "toolchain preflight marked gate skippable";
|
|
188
213
|
const remedy = missing?.remedy ?? remedyForGate(gateId, cause);
|
|
189
214
|
process.stderr.write(`check: skipping gate ${gateId} (degraded) — cause: ${cause}; remedy: ${remedy}\n`);
|
|
@@ -15,6 +15,20 @@ export type CheckGateSpec = string | {
|
|
|
15
15
|
* xbrief/completed instead of skipping (#3357).
|
|
16
16
|
*/
|
|
17
17
|
export declare const PRODUCT_FIRST_AC_GATE: CheckGateSpec;
|
|
18
|
+
/**
|
|
19
|
+
* Candidate-scoped orphan-active for check aggregates (#3893).
|
|
20
|
+
*
|
|
21
|
+
* The unscoped sweep on the merge chokepoint gave a brief stranded by one
|
|
22
|
+
* merge authority over every other open PR, and N stranded briefs made N
|
|
23
|
+
* single-brief lifecycle PRs mutually unmergeable. It was never preventive for
|
|
24
|
+
* the candidate either: that candidate's linked PR still reads
|
|
25
|
+
* `merged_at: null` while its own gate runs.
|
|
26
|
+
*
|
|
27
|
+
* Bare `verify:orphan-active` stays repo-wide for `deft doctor`, manual runs,
|
|
28
|
+
* swarm finalize, and the after-merge `--issue N` DONE gate (#3429); the
|
|
29
|
+
* scoped form still falls back to the full sweep at the delivery tip.
|
|
30
|
+
*/
|
|
31
|
+
export declare const ORPHAN_ACTIVE_MERGE_GATE: CheckGateSpec;
|
|
18
32
|
export declare function checkGateId(spec: CheckGateSpec): string;
|
|
19
33
|
/** Args for `task … --taskfile <path>` (optional `--` + public CLI flags). */
|
|
20
34
|
export declare function checkGateSpawnArgs(spec: CheckGateSpec, taskfilePath: string): string[];
|
package/dist/check/gate-lists.js
CHANGED
|
@@ -9,6 +9,23 @@ export const PRODUCT_FIRST_AC_GATE = {
|
|
|
9
9
|
task: PRODUCT_AC_GATE_ID,
|
|
10
10
|
args: ["--soft-missing-xbrief"],
|
|
11
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Candidate-scoped orphan-active for check aggregates (#3893).
|
|
14
|
+
*
|
|
15
|
+
* The unscoped sweep on the merge chokepoint gave a brief stranded by one
|
|
16
|
+
* merge authority over every other open PR, and N stranded briefs made N
|
|
17
|
+
* single-brief lifecycle PRs mutually unmergeable. It was never preventive for
|
|
18
|
+
* the candidate either: that candidate's linked PR still reads
|
|
19
|
+
* `merged_at: null` while its own gate runs.
|
|
20
|
+
*
|
|
21
|
+
* Bare `verify:orphan-active` stays repo-wide for `deft doctor`, manual runs,
|
|
22
|
+
* swarm finalize, and the after-merge `--issue N` DONE gate (#3429); the
|
|
23
|
+
* scoped form still falls back to the full sweep at the delivery tip.
|
|
24
|
+
*/
|
|
25
|
+
export const ORPHAN_ACTIVE_MERGE_GATE = {
|
|
26
|
+
task: "verify:orphan-active",
|
|
27
|
+
args: ["--changed-only"],
|
|
28
|
+
};
|
|
12
29
|
export function checkGateId(spec) {
|
|
13
30
|
return typeof spec === "string" ? spec : spec.task;
|
|
14
31
|
}
|
|
@@ -62,8 +79,9 @@ export const FRAMEWORK_CHECK_GATES = [
|
|
|
62
79
|
// --- Fast preflight (seconds–few min) — #3188 ---
|
|
63
80
|
"verify:branch",
|
|
64
81
|
"verify:encoding",
|
|
82
|
+
"verify:closing-keywords",
|
|
65
83
|
"verify:cache-fresh",
|
|
66
|
-
|
|
84
|
+
ORPHAN_ACTIVE_MERGE_GATE,
|
|
67
85
|
"verify:completed-write-guard",
|
|
68
86
|
"verify:license-sync",
|
|
69
87
|
"verify:contract-drift",
|
|
@@ -73,7 +91,10 @@ export const FRAMEWORK_CHECK_GATES = [
|
|
|
73
91
|
"verify:rule-ownership",
|
|
74
92
|
"verify:biome-config",
|
|
75
93
|
"verify:content-manifest",
|
|
94
|
+
// #3900 check 1: C1 declaration vs staged pack. Checks 2/3 compose C3/C2.
|
|
95
|
+
"verify:deposit-closure",
|
|
76
96
|
"verify:skill-external-fetch-gate",
|
|
97
|
+
"verify:semantic-single-source",
|
|
77
98
|
"verify:cursor-tier1",
|
|
78
99
|
"verify:openclaw-tier1",
|
|
79
100
|
"verify:go-freeze",
|
|
@@ -82,7 +103,9 @@ export const FRAMEWORK_CHECK_GATES = [
|
|
|
82
103
|
// #3145: test/source boundary + approved-scope provenance + consumer gate composition
|
|
83
104
|
"verify:test-boundary",
|
|
84
105
|
"verify:scope-provenance",
|
|
85
|
-
|
|
106
|
+
// #3893: fail-closed on merge-chokepoint gate scoping for the composition
|
|
107
|
+
// this repo owns; consumer deposits stay warn-only until `deft update`.
|
|
108
|
+
{ task: "verify:consumer-check-contract", args: ["--framework-source"] },
|
|
86
109
|
// #3362: dead-surface detector (warn-only this release; no --enforce)
|
|
87
110
|
"verify:telemetry-coverage",
|
|
88
111
|
"verify:vbrief-conformance",
|
|
@@ -111,7 +134,7 @@ export const CONSUMER_CHECK_GATES = [
|
|
|
111
134
|
"verify:branch",
|
|
112
135
|
"verify:cache-fresh",
|
|
113
136
|
"verify:wip-cap",
|
|
114
|
-
|
|
137
|
+
ORPHAN_ACTIVE_MERGE_GATE,
|
|
115
138
|
"verify:completed-write-guard",
|
|
116
139
|
"doctor",
|
|
117
140
|
"toolchain:check-consumer",
|
|
@@ -13,7 +13,7 @@ const GATE_REMEDIES = {
|
|
|
13
13
|
"verify:wip-cap": "Demote stale pending scopes (task scope:demote) or raise plan.policy.wipCap deliberately",
|
|
14
14
|
doctor: "Run task doctor and follow the named recovery steps",
|
|
15
15
|
"toolchain:check": "Install missing maintainer tools reported by the gate (go, uv, git, gh, node, pnpm)",
|
|
16
|
-
"toolchain:check-consumer": "Install missing consumer
|
|
16
|
+
"toolchain:check-consumer": "Install the missing consumer tool reported by the gate; use npm from Node or enable pnpm with Corepack as declared by package.json",
|
|
17
17
|
"ts:check-lane": "Fix lint/type/test failures; re-run task ts:check-lane",
|
|
18
18
|
"vbrief:validate": "Fix xBRIEF/vBRIEF schema errors reported by the gate",
|
|
19
19
|
"verify-strategy-output": "Re-run strategy output or fix non-conformant scope filenames / PROJECT-DEFINITION",
|
|
@@ -57,6 +57,12 @@ export function extractGateCause(stdout, stderr, exitCode, spawnError, gateId) {
|
|
|
57
57
|
useful.push(line);
|
|
58
58
|
}
|
|
59
59
|
const gateHint = gateId?.trim() ?? "";
|
|
60
|
+
if (gateHint === "toolchain:check" || gateHint === "toolchain:check-consumer") {
|
|
61
|
+
const toolFailure = useful.find((line) => /^(?:package manager|go|uv|git|gh|node|npm|pnpm|task): (?:NOT FOUND|FAILED|ERROR)\b/i.test(line));
|
|
62
|
+
if (toolFailure !== undefined) {
|
|
63
|
+
return sanitizeCauseLine(toolFailure);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
60
66
|
if (gateHint.length > 0) {
|
|
61
67
|
const named = useful.find((line) => line.includes(gateHint));
|
|
62
68
|
if (named !== undefined) {
|
|
@@ -106,14 +112,23 @@ export function remedyForGate(gateId, cause) {
|
|
|
106
112
|
return CLI_SPAWN_ERROR_REMEDY;
|
|
107
113
|
}
|
|
108
114
|
if (/task binary not found|cannot spawn go-task/i.test(cause)) {
|
|
109
|
-
if (gateId.startsWith("verify:") ||
|
|
115
|
+
if (gateId.startsWith("verify:") ||
|
|
116
|
+
gateId.startsWith("verify-") ||
|
|
117
|
+
gateId === "doctor" ||
|
|
118
|
+
gateId === "toolchain:check-consumer") {
|
|
110
119
|
return CLI_SPAWN_ERROR_REMEDY;
|
|
111
120
|
}
|
|
112
121
|
return SPAWN_ERROR_REMEDY;
|
|
113
122
|
}
|
|
114
|
-
if (/
|
|
123
|
+
if (/Unsupported DEFT_PACKAGE_MANAGER value/i.test(cause)) {
|
|
124
|
+
return "Set DEFT_PACKAGE_MANAGER to npm or pnpm, or unset it to use package.json; then re-run the consumer check";
|
|
125
|
+
}
|
|
126
|
+
if (/\bpnpm(?: binary not found|: (?:NOT FOUND|FAILED|ERROR))/i.test(cause)) {
|
|
115
127
|
return "Enable pnpm: corepack enable && corepack prepare pnpm@latest --activate";
|
|
116
128
|
}
|
|
129
|
+
if (/\bnpm(?: binary not found|: (?:NOT FOUND|FAILED|ERROR))/i.test(cause)) {
|
|
130
|
+
return "Install or repair Node 20+ (npm is bundled), then re-run the consumer check";
|
|
131
|
+
}
|
|
117
132
|
return (GATE_REMEDIES[gateId] ??
|
|
118
133
|
`Re-run the gate for details: task ${gateId} (or task check); fix the reported product/process defect`);
|
|
119
134
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
/** One remediation when check cannot target the just-completed brief (#3357). */
|
|
9
9
|
export declare const SESSION_COMPLETED_AC_REMEDIATION = "Run task verify:ac -- xbrief/completed/<just-completed>.xbrief.json (a story completed this session; check must not soft-skip) (#3357)";
|
|
10
10
|
/** Project-relative marker written by scope:complete for this session (#3357). */
|
|
11
|
-
export declare const SESSION_COMPLETED_MARKER_REL: readonly [".deft", "last-completed.json"];
|
|
11
|
+
export declare const SESSION_COMPLETED_MARKER_REL: readonly [".deft", "cache", "last-completed.json"];
|
|
12
12
|
export interface SessionCompletedMarker {
|
|
13
13
|
readonly path: string;
|
|
14
14
|
readonly sessionId: string;
|
|
@@ -13,7 +13,7 @@ import { parseTimestamp } from "../session/time.js";
|
|
|
13
13
|
/** One remediation when check cannot target the just-completed brief (#3357). */
|
|
14
14
|
export const SESSION_COMPLETED_AC_REMEDIATION = "Run task verify:ac -- xbrief/completed/<just-completed>.xbrief.json (a story completed this session; check must not soft-skip) (#3357)";
|
|
15
15
|
/** Project-relative marker written by scope:complete for this session (#3357). */
|
|
16
|
-
export const SESSION_COMPLETED_MARKER_REL = [".deft", "last-completed.json"];
|
|
16
|
+
export const SESSION_COMPLETED_MARKER_REL = [".deft", "cache", "last-completed.json"];
|
|
17
17
|
function asRecord(value) {
|
|
18
18
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
19
19
|
return value;
|
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { contentRoot } from "../content-root.js";
|
|
7
7
|
import { resolveProjectDefinitionPath } from "../layout/resolve.js";
|
|
8
8
|
import { readPlanPolicy } from "../policy/plan-extensions.js";
|
|
9
|
+
import { resolveCaptureFailureStderr, SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
9
10
|
import { loadJsonFile } from "../verify-source/code-structure-validate.js";
|
|
10
11
|
import { CODEBASE_MAP_SCHEMA_PATH } from "./constants.js";
|
|
11
12
|
import { buildCodebaseMap, CodeStructureConfigError, configErrorToDict, defaultCodeStructurePath, fileSha256, } from "./default-extractor.js";
|
|
@@ -547,6 +548,7 @@ function runProviderCommand(command, cwd) {
|
|
|
547
548
|
cwd,
|
|
548
549
|
encoding: "utf8",
|
|
549
550
|
timeout: 60_000,
|
|
551
|
+
maxBuffer: SUBPROCESS_MAX_BUFFER,
|
|
550
552
|
stdio: ["ignore", "pipe", "pipe"],
|
|
551
553
|
});
|
|
552
554
|
return { returncode: 0, stdout, stderr: "" };
|
|
@@ -556,7 +558,11 @@ function runProviderCommand(command, cwd) {
|
|
|
556
558
|
return {
|
|
557
559
|
returncode: typeof e.status === "number" ? e.status : 1,
|
|
558
560
|
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
559
|
-
stderr:
|
|
561
|
+
stderr: resolveCaptureFailureStderr({
|
|
562
|
+
captured: typeof e.stderr === "string" ? e.stderr : "",
|
|
563
|
+
status: e.status,
|
|
564
|
+
message: e.message ?? String(err),
|
|
565
|
+
}),
|
|
560
566
|
};
|
|
561
567
|
}
|
|
562
568
|
}
|
|
@@ -10,6 +10,20 @@
|
|
|
10
10
|
import { type CheckGateSpec } from "../check/gate-lists.js";
|
|
11
11
|
/** Gates that #3145 requires on consumer check composition (beyond baseline). */
|
|
12
12
|
export declare const REQUIRED_CONSUMER_ENFORCEMENT_GATES: readonly string[];
|
|
13
|
+
/**
|
|
14
|
+
* Gates whose composition on a check aggregate must carry a scoping argument
|
|
15
|
+
* (#3893).
|
|
16
|
+
*
|
|
17
|
+
* `verify:orphan-active` is repo-wide by default. Composed unscoped on a merge
|
|
18
|
+
* chokepoint it fails a candidate for residue another merge stranded, and N
|
|
19
|
+
* stranded briefs make N single-brief lifecycle PRs mutually unmergeable. It is
|
|
20
|
+
* not preventive for the candidate either: that candidate's linked PR still
|
|
21
|
+
* reads `merged_at: null` while its own gate runs.
|
|
22
|
+
*
|
|
23
|
+
* Fail-closed under `--framework-source`, where this repo owns the composition;
|
|
24
|
+
* a warning elsewhere while `deft update` re-deposits the Taskfile.
|
|
25
|
+
*/
|
|
26
|
+
export declare const MERGE_CHOKEPOINT_SCOPED_GATE_ARGS: ReadonlyMap<string, string>;
|
|
13
27
|
export interface ConsumerCheckContractFinding {
|
|
14
28
|
readonly gateId: string;
|
|
15
29
|
readonly surface: "check-task" | "ci-workflow" | "verify-taskfile";
|
|
@@ -150,11 +164,44 @@ export declare function stripTaskBodyComments(body: string): string;
|
|
|
150
164
|
export declare function taskBodyInvokesCheckOrchestrator(body: string): boolean;
|
|
151
165
|
/** True when the check / check:consumer / check:framework-source task invokes orchestrator. */
|
|
152
166
|
export declare function taskfileInvokesCheckOrchestrator(text: string): boolean;
|
|
167
|
+
/** One `deps:` entry plus the YAML nested under it (`vars:` and friends). */
|
|
168
|
+
export interface CheckDepEntry {
|
|
169
|
+
readonly name: string;
|
|
170
|
+
readonly body: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Extract `deps:` entries from a go-task task definition, keeping each entry's
|
|
174
|
+
* nested body so an argument-carrying dep (#3893) is distinguishable from a
|
|
175
|
+
* bare one. Best-effort line parser.
|
|
176
|
+
*/
|
|
177
|
+
export declare function extractCheckDepEntries(taskfileText: string, taskName: string): CheckDepEntry[];
|
|
153
178
|
/**
|
|
154
179
|
* Extract dependency task names from a go-task task definition body snippet.
|
|
155
180
|
* Best-effort line parser for `deps:` list entries.
|
|
156
181
|
*/
|
|
157
182
|
export declare function extractCheckDeps(taskfileText: string, taskName: string): string[];
|
|
183
|
+
/**
|
|
184
|
+
* Drop a YAML trailing comment and surrounding quotes from a scalar value.
|
|
185
|
+
* Honours double-quoted `\\"` escapes and single-quoted `''` doubling, so a
|
|
186
|
+
* value carrying a quote is not truncated before the argument that follows.
|
|
187
|
+
*/
|
|
188
|
+
export declare function parseYamlScalar(raw: string): string;
|
|
189
|
+
/**
|
|
190
|
+
* Effective `CLI_ARGS` value for a `deps:` entry, or null when it sets none.
|
|
191
|
+
*
|
|
192
|
+
* Reads the key itself rather than the entry text, so the required argument
|
|
193
|
+
* appearing in a comment, a sibling variable, or a descriptive value cannot
|
|
194
|
+
* stand in for the argument the gate actually receives (#3893).
|
|
195
|
+
*/
|
|
196
|
+
export declare function depEntryCliArgs(body: string): string | null;
|
|
197
|
+
/**
|
|
198
|
+
* True when the effective `CLI_ARGS` token list carries `requiredArg`.
|
|
199
|
+
*
|
|
200
|
+
* Exact token only: the guarded verbs accept the bare flag, so an equals form
|
|
201
|
+
* like `--changed-only=0` would exit 2 on an unrecognized argument while the
|
|
202
|
+
* contract reported the composition healthy.
|
|
203
|
+
*/
|
|
204
|
+
export declare function cliArgsCarry(cliArgs: string | null, requiredArg: string): boolean;
|
|
158
205
|
/**
|
|
159
206
|
* Evaluate whether required enforcement gates are composed into consumer check/CI.
|
|
160
207
|
*/
|
|
@@ -17,6 +17,22 @@ export const REQUIRED_CONSUMER_ENFORCEMENT_GATES = [
|
|
|
17
17
|
"verify:scope-provenance",
|
|
18
18
|
"verify:consumer-check-contract",
|
|
19
19
|
];
|
|
20
|
+
/**
|
|
21
|
+
* Gates whose composition on a check aggregate must carry a scoping argument
|
|
22
|
+
* (#3893).
|
|
23
|
+
*
|
|
24
|
+
* `verify:orphan-active` is repo-wide by default. Composed unscoped on a merge
|
|
25
|
+
* chokepoint it fails a candidate for residue another merge stranded, and N
|
|
26
|
+
* stranded briefs make N single-brief lifecycle PRs mutually unmergeable. It is
|
|
27
|
+
* not preventive for the candidate either: that candidate's linked PR still
|
|
28
|
+
* reads `merged_at: null` while its own gate runs.
|
|
29
|
+
*
|
|
30
|
+
* Fail-closed under `--framework-source`, where this repo owns the composition;
|
|
31
|
+
* a warning elsewhere while `deft update` re-deposits the Taskfile.
|
|
32
|
+
*/
|
|
33
|
+
export const MERGE_CHOKEPOINT_SCOPED_GATE_ARGS = new Map([
|
|
34
|
+
["verify:orphan-active", "--changed-only"],
|
|
35
|
+
]);
|
|
20
36
|
/**
|
|
21
37
|
* Relative path forms accepted for the deft-install canonical Taskfile include
|
|
22
38
|
* (init-deposit `MINIMAL_TASKFILE` / `CANONICAL_TASKFILE_INCLUDE`).
|
|
@@ -575,16 +591,18 @@ export function taskfileInvokesCheckOrchestrator(text) {
|
|
|
575
591
|
return false;
|
|
576
592
|
}
|
|
577
593
|
/**
|
|
578
|
-
* Extract
|
|
579
|
-
*
|
|
594
|
+
* Extract `deps:` entries from a go-task task definition, keeping each entry's
|
|
595
|
+
* nested body so an argument-carrying dep (#3893) is distinguishable from a
|
|
596
|
+
* bare one. Best-effort line parser.
|
|
580
597
|
*/
|
|
581
|
-
export function
|
|
598
|
+
export function extractCheckDepEntries(taskfileText, taskName) {
|
|
582
599
|
const lines = taskfileText.replace(/\r\n/g, "\n").split("\n");
|
|
583
|
-
const
|
|
600
|
+
const entries = [];
|
|
584
601
|
let inTask = false;
|
|
585
602
|
let taskIndent = 0;
|
|
586
603
|
let inDeps = false;
|
|
587
604
|
let depsIndent = 0;
|
|
605
|
+
let current = null;
|
|
588
606
|
const taskRe = new RegExp(`^${escapeRegExp(taskName)}\\s*:`);
|
|
589
607
|
for (const raw of lines) {
|
|
590
608
|
const stripped = raw.trim();
|
|
@@ -604,23 +622,142 @@ export function extractCheckDeps(taskfileText, taskName) {
|
|
|
604
622
|
if (/^deps\s*:/.test(stripped)) {
|
|
605
623
|
inDeps = true;
|
|
606
624
|
depsIndent = indent;
|
|
625
|
+
current = null;
|
|
607
626
|
continue;
|
|
608
627
|
}
|
|
609
|
-
if (inDeps)
|
|
610
|
-
|
|
611
|
-
|
|
628
|
+
if (!inDeps)
|
|
629
|
+
continue;
|
|
630
|
+
if (indent <= depsIndent && !stripped.startsWith("-")) {
|
|
631
|
+
inDeps = false;
|
|
632
|
+
current = null;
|
|
633
|
+
}
|
|
634
|
+
else if (stripped.startsWith("-")) {
|
|
635
|
+
// - verify:branch OR - task: verify:branch
|
|
636
|
+
const m = stripped.match(/^-\s+task:\s*["']?([^"'#]+?)["']?\s*(?:#.*)?$/) ??
|
|
637
|
+
stripped.match(/^-\s+["']?([^"'#]+?)["']?\s*(?:#.*)?$/);
|
|
638
|
+
current = m?.[1] === undefined ? null : { name: m[1].trim(), lines: [] };
|
|
639
|
+
if (current !== null) {
|
|
640
|
+
entries.push(current);
|
|
612
641
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
642
|
+
}
|
|
643
|
+
else if (current !== null) {
|
|
644
|
+
// Keep indentation: the scoping check below needs to tell an immediate
|
|
645
|
+
// `vars:` property from deeper YAML (#3893).
|
|
646
|
+
current.lines.push(raw);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return entries.map((entry) => ({ name: entry.name, body: entry.lines.join("\n") }));
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Extract dependency task names from a go-task task definition body snippet.
|
|
653
|
+
* Best-effort line parser for `deps:` list entries.
|
|
654
|
+
*/
|
|
655
|
+
export function extractCheckDeps(taskfileText, taskName) {
|
|
656
|
+
return extractCheckDepEntries(taskfileText, taskName).map((entry) => entry.name);
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Drop a YAML trailing comment and surrounding quotes from a scalar value.
|
|
660
|
+
* Honours double-quoted `\\"` escapes and single-quoted `''` doubling, so a
|
|
661
|
+
* value carrying a quote is not truncated before the argument that follows.
|
|
662
|
+
*/
|
|
663
|
+
export function parseYamlScalar(raw) {
|
|
664
|
+
const text = raw.trim();
|
|
665
|
+
if (text.startsWith('"')) {
|
|
666
|
+
let out = "";
|
|
667
|
+
for (let i = 1; i < text.length; i += 1) {
|
|
668
|
+
const ch = text[i];
|
|
669
|
+
if (ch === "\\" && i + 1 < text.length) {
|
|
670
|
+
out += text[i + 1];
|
|
671
|
+
i += 1;
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if (ch === '"')
|
|
675
|
+
return out;
|
|
676
|
+
out += ch;
|
|
677
|
+
}
|
|
678
|
+
return out;
|
|
679
|
+
}
|
|
680
|
+
if (text.startsWith("'")) {
|
|
681
|
+
let out = "";
|
|
682
|
+
for (let i = 1; i < text.length; i += 1) {
|
|
683
|
+
const ch = text[i];
|
|
684
|
+
if (ch === "'") {
|
|
685
|
+
if (text[i + 1] === "'") {
|
|
686
|
+
out += "'";
|
|
687
|
+
i += 1;
|
|
688
|
+
continue;
|
|
619
689
|
}
|
|
690
|
+
return out;
|
|
620
691
|
}
|
|
692
|
+
out += ch;
|
|
621
693
|
}
|
|
694
|
+
return out;
|
|
622
695
|
}
|
|
623
|
-
|
|
696
|
+
const comment = text.indexOf(" #");
|
|
697
|
+
return (comment === -1 ? text : text.slice(0, comment)).trim();
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Inline-flow `vars: { CLI_ARGS: ... }` scalar. Quote escapes are honoured so a
|
|
701
|
+
* value carrying a quote is not truncated before the argument that follows.
|
|
702
|
+
*/
|
|
703
|
+
const INLINE_CLI_ARGS_RE = /CLI_ARGS\s*:\s*("(?:\\.|[^"\\])*"|'(?:''|[^'])*'|[^,}]*)/;
|
|
704
|
+
/**
|
|
705
|
+
* Effective `CLI_ARGS` value for a `deps:` entry, or null when it sets none.
|
|
706
|
+
*
|
|
707
|
+
* Reads the key itself rather than the entry text, so the required argument
|
|
708
|
+
* appearing in a comment, a sibling variable, or a descriptive value cannot
|
|
709
|
+
* stand in for the argument the gate actually receives (#3893).
|
|
710
|
+
*/
|
|
711
|
+
export function depEntryCliArgs(body) {
|
|
712
|
+
let varsIndent = null;
|
|
713
|
+
let propIndent = null;
|
|
714
|
+
let value = null;
|
|
715
|
+
for (const rawLine of body.split("\n")) {
|
|
716
|
+
const line = rawLine.trim();
|
|
717
|
+
if (line.length === 0 || line.startsWith("#"))
|
|
718
|
+
continue;
|
|
719
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
720
|
+
if (varsIndent !== null && indent <= varsIndent) {
|
|
721
|
+
varsIndent = null;
|
|
722
|
+
propIndent = null;
|
|
723
|
+
}
|
|
724
|
+
const varsBlock = /^vars\s*:\s*(.*)$/.exec(line);
|
|
725
|
+
if (varsBlock !== null) {
|
|
726
|
+
varsIndent = indent;
|
|
727
|
+
propIndent = null;
|
|
728
|
+
// Inline flow form: vars: { CLI_ARGS: "--changed-only" }
|
|
729
|
+
const inline = INLINE_CLI_ARGS_RE.exec(varsBlock[1] ?? "");
|
|
730
|
+
if (inline !== null) {
|
|
731
|
+
value = parseYamlScalar(inline[1] ?? "");
|
|
732
|
+
}
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
if (varsIndent === null)
|
|
736
|
+
continue;
|
|
737
|
+
propIndent ??= indent;
|
|
738
|
+
if (indent !== propIndent)
|
|
739
|
+
continue;
|
|
740
|
+
const cliArgs = /^CLI_ARGS\s*:\s*(.*)$/.exec(line);
|
|
741
|
+
if (cliArgs !== null) {
|
|
742
|
+
value = parseYamlScalar(cliArgs[1] ?? "");
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
return value;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* True when the effective `CLI_ARGS` token list carries `requiredArg`.
|
|
749
|
+
*
|
|
750
|
+
* Exact token only: the guarded verbs accept the bare flag, so an equals form
|
|
751
|
+
* like `--changed-only=0` would exit 2 on an unrecognized argument while the
|
|
752
|
+
* contract reported the composition healthy.
|
|
753
|
+
*/
|
|
754
|
+
export function cliArgsCarry(cliArgs, requiredArg) {
|
|
755
|
+
if (cliArgs === null)
|
|
756
|
+
return false;
|
|
757
|
+
return cliArgs
|
|
758
|
+
.split(/\s+/)
|
|
759
|
+
.filter((token) => token.length > 0)
|
|
760
|
+
.some((token) => token === requiredArg);
|
|
624
761
|
}
|
|
625
762
|
function remediationForMissing(gateId, surface) {
|
|
626
763
|
return (`Add \`${gateId}\` to the consumer ${surface} composition (Taskfile check deps ` +
|
|
@@ -712,12 +849,41 @@ export function evaluateConsumerCheckContract(projectRoot, options = {}) {
|
|
|
712
849
|
}
|
|
713
850
|
let anyAggregateDefined = false;
|
|
714
851
|
for (const target of checkTargets) {
|
|
715
|
-
const
|
|
852
|
+
const entries = extractCheckDepEntries(rootTaskfile, target);
|
|
853
|
+
const deps = entries.map((entry) => entry.name);
|
|
716
854
|
const body = extractTaskBody(rootTaskfile, target);
|
|
717
855
|
const defined = deps.length > 0 || body.trim().length > 0;
|
|
718
856
|
if (!defined)
|
|
719
857
|
continue;
|
|
720
858
|
anyAggregateDefined = true;
|
|
859
|
+
// Checked even on a trusted orchestrator body: a listed dep still runs, and
|
|
860
|
+
// unscoped on a merge chokepoint is the #3893 defect.
|
|
861
|
+
for (const [gateId, requiredArg] of MERGE_CHOKEPOINT_SCOPED_GATE_ARGS) {
|
|
862
|
+
// Every occurrence must carry the argument: a scoped entry followed by a
|
|
863
|
+
// bare duplicate still runs the repo-wide scan (#3893).
|
|
864
|
+
const listed = entries.filter((row) => row.name === gateId);
|
|
865
|
+
if (listed.length === 0)
|
|
866
|
+
continue;
|
|
867
|
+
if (listed.every((row) => cliArgsCarry(depEntryCliArgs(row.body), requiredArg)))
|
|
868
|
+
continue;
|
|
869
|
+
const finding = {
|
|
870
|
+
gateId,
|
|
871
|
+
surface: "check-task",
|
|
872
|
+
detail: `aggregate '${target}' composes ${gateId} without ${requiredArg}: an unscoped ` +
|
|
873
|
+
"repo-wide lifecycle scan on a merge chokepoint fails a candidate for residue " +
|
|
874
|
+
"another merge stranded (#3893)",
|
|
875
|
+
remediation: `Pass ${requiredArg} to ${gateId} in the '${target}' deps (go-task object form, ` +
|
|
876
|
+
`vars: CLI_ARGS: "${requiredArg}"). Bare ${gateId} stays repo-wide for doctor, ` +
|
|
877
|
+
"manual runs, and the after-merge --issue N run. " +
|
|
878
|
+
"See content/docs/consumer-check-contract.md (#3893).",
|
|
879
|
+
};
|
|
880
|
+
if (options.frameworkSource === true) {
|
|
881
|
+
findings.push(finding);
|
|
882
|
+
}
|
|
883
|
+
else {
|
|
884
|
+
soft.push(finding);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
721
887
|
const trustThis = taskInvokesOrchestrator(target) && verifyDefinesRequired;
|
|
722
888
|
if (trustThis)
|
|
723
889
|
continue;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Loads durable unit state and returns a single deterministic decision
|
|
5
5
|
* before every delivery dispatch or retry.
|
|
6
6
|
*/
|
|
7
|
-
import type { DeliveryUnitLedger, PreDispatchInput, PreDispatchResult } from "./types.js";
|
|
7
|
+
import type { DeliveryBudgetPolicy, DeliveryUnitLedger, PreDispatchInput, PreDispatchResult } from "./types.js";
|
|
8
8
|
/**
|
|
9
9
|
* Evaluate whether a delivery dispatch may proceed.
|
|
10
10
|
*
|
|
@@ -15,6 +15,14 @@ import type { DeliveryUnitLedger, PreDispatchInput, PreDispatchResult } from "./
|
|
|
15
15
|
* That keeps bounded override quota for dispatches that truly need it.
|
|
16
16
|
*/
|
|
17
17
|
export declare function evaluatePreDispatch(ledger: DeliveryUnitLedger, input: PreDispatchInput): PreDispatchResult;
|
|
18
|
+
/**
|
|
19
|
+
* Elapsed budget for a run already queued or running (#3983).
|
|
20
|
+
* Pre-dispatch cannot see this case: an active attempt is DENY_DUPLICATE_ACTIVE.
|
|
21
|
+
*/
|
|
22
|
+
export declare function evaluateInFlight(ledger: DeliveryUnitLedger, input?: {
|
|
23
|
+
readonly now?: string;
|
|
24
|
+
readonly policy?: Partial<DeliveryBudgetPolicy>;
|
|
25
|
+
}): PreDispatchResult;
|
|
18
26
|
/**
|
|
19
27
|
* Convenience: evaluate against ledger, and if blocked, return handoff suitable
|
|
20
28
|
* for persistence via markBlocked + saveUnitLedger.
|