dorfl 0.1.1 → 0.1.2
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/advance-ci-template.d.ts +3 -3
- package/dist/advance-ci-template.js +1 -1
- package/dist/advance-ci-template.js.map +1 -1
- package/dist/advance-classify.d.ts +5 -5
- package/dist/advance-classify.d.ts.map +1 -1
- package/dist/advance-classify.js +4 -4
- package/dist/advance-drivers.d.ts +7 -7
- package/dist/advance-drivers.d.ts.map +1 -1
- package/dist/advance-drivers.js +5 -5
- package/dist/advance-drivers.js.map +1 -1
- package/dist/advance-isolated.d.ts +3 -3
- package/dist/advance-isolated.d.ts.map +1 -1
- package/dist/advance-isolated.js +1 -1
- package/dist/advance-lifecycle-template.d.ts +2 -2
- package/dist/advance-lifecycle-template.js +9 -9
- package/dist/advance-lifecycle-template.js.map +1 -1
- package/dist/advance-loop-driver.d.ts +3 -3
- package/dist/advance-loop-driver.d.ts.map +1 -1
- package/dist/advance-loop-driver.js +1 -1
- package/dist/advance-treeless-publish.d.ts +1 -1
- package/dist/advance.d.ts +11 -11
- package/dist/advance.d.ts.map +1 -1
- package/dist/advance.js +21 -21
- package/dist/advance.js.map +1 -1
- package/dist/advancing-lock.d.ts +1 -1
- package/dist/advancing-lock.js +5 -5
- package/dist/apply-decide.d.ts +2 -2
- package/dist/apply-decide.js +2 -2
- package/dist/apply-merge-action.d.ts +4 -4
- package/dist/apply-merge-action.js +2 -2
- package/dist/apply-persist.d.ts +5 -5
- package/dist/apply-persist.d.ts.map +1 -1
- package/dist/apply-persist.js +7 -7
- package/dist/apply-persist.js.map +1 -1
- package/dist/buildable-body.d.ts +14 -14
- package/dist/buildable-body.js +9 -9
- package/dist/claim-cas.d.ts +3 -3
- package/dist/claim-cas.js +1 -1
- package/dist/claim-cas.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +76 -76
- package/dist/cli.js.map +1 -1
- package/dist/close-job-template.d.ts +3 -3
- package/dist/close-job-template.js +8 -8
- package/dist/close-job.d.ts +8 -8
- package/dist/close-job.js +25 -25
- package/dist/close-job.js.map +1 -1
- package/dist/complete.d.ts +3 -3
- package/dist/complete.js +8 -8
- package/dist/complete.js.map +1 -1
- package/dist/concurrency.d.ts +1 -1
- package/dist/concurrency.js +1 -1
- package/dist/config.d.ts +32 -32
- package/dist/config.js +5 -5
- package/dist/config.js.map +1 -1
- package/dist/continue-branch.d.ts +1 -1
- package/dist/continue-branch.js +1 -1
- package/dist/cwd-section.js +1 -1
- package/dist/cwd-section.js.map +1 -1
- package/dist/decision-engine.d.ts +2 -2
- package/dist/do-autopick.d.ts +6 -6
- package/dist/do-autopick.d.ts.map +1 -1
- package/dist/do-autopick.js +5 -5
- package/dist/do-autopick.js.map +1 -1
- package/dist/do-config.d.ts +3 -3
- package/dist/do-config.js +3 -3
- package/dist/do-config.js.map +1 -1
- package/dist/do-remote-auto.d.ts +2 -2
- package/dist/do-remote-auto.js +1 -1
- package/dist/do.d.ts +25 -25
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +20 -20
- package/dist/do.js.map +1 -1
- package/dist/drop-source.d.ts +2 -2
- package/dist/env-config.js +8 -8
- package/dist/env-config.js.map +1 -1
- package/dist/format.js +3 -3
- package/dist/format.js.map +1 -1
- package/dist/frontmatter.d.ts +14 -13
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +12 -24
- package/dist/frontmatter.js.map +1 -1
- package/dist/install-ci-branch-protection.d.ts +1 -1
- package/dist/install-ci-branch-protection.js +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.d.ts +1 -1
- package/dist/install-ci-capabilities/advance-lifecycle.js +1 -1
- package/dist/install-ci-capabilities/close-job.d.ts +1 -1
- package/dist/install-ci-capabilities/close-job.js +1 -1
- package/dist/install-ci-capabilities/example-noop.d.ts +1 -1
- package/dist/install-ci-capabilities/example-noop.js +1 -1
- package/dist/install-ci-capabilities/intake.d.ts +2 -2
- package/dist/install-ci-capabilities/intake.js +2 -2
- package/dist/install-ci-capabilities/verify.d.ts +1 -1
- package/dist/install-ci-capabilities/verify.js +1 -1
- package/dist/install-ci-core.d.ts +3 -3
- package/dist/install-ci-core.js +2 -2
- package/dist/install-ci-core.js.map +1 -1
- package/dist/install-ci-github.d.ts +1 -1
- package/dist/install-ci-github.js +1 -1
- package/dist/install-ci.d.ts +1 -1
- package/dist/install-ci.js +4 -4
- package/dist/install-ci.js.map +1 -1
- package/dist/intake-event.d.ts +6 -6
- package/dist/intake-event.js +6 -6
- package/dist/intake-marker.d.ts +3 -3
- package/dist/intake-marker.d.ts.map +1 -1
- package/dist/intake-triage.d.ts +1 -1
- package/dist/intake-triage.js +2 -2
- package/dist/intake-trigger-template.d.ts +8 -8
- package/dist/intake-trigger-template.d.ts.map +1 -1
- package/dist/intake-trigger-template.js +16 -16
- package/dist/intake-trigger-template.js.map +1 -1
- package/dist/intake.d.ts +50 -50
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +70 -70
- package/dist/intake.js.map +1 -1
- package/dist/integration-core.d.ts +17 -17
- package/dist/integration-core.js +17 -17
- package/dist/integration-core.js.map +1 -1
- package/dist/isolation.d.ts +3 -3
- package/dist/issue-provider.d.ts +4 -4
- package/dist/issue-provider.js +1 -1
- package/dist/item-lock.d.ts +21 -21
- package/dist/item-lock.d.ts.map +1 -1
- package/dist/item-lock.js +16 -16
- package/dist/item-path.d.ts +2 -2
- package/dist/item-path.js +2 -2
- package/dist/ledger-lint.d.ts +9 -9
- package/dist/ledger-lint.js +9 -9
- package/dist/ledger-read.d.ts +57 -57
- package/dist/ledger-read.d.ts.map +1 -1
- package/dist/ledger-read.js +24 -24
- package/dist/ledger-read.js.map +1 -1
- package/dist/ledger-write.d.ts +2 -2
- package/dist/ledger-write.js +1 -1
- package/dist/lifecycle-gather.d.ts +1 -1
- package/dist/lifecycle-gather.js +16 -16
- package/dist/lifecycle-gather.js.map +1 -1
- package/dist/lifecycle-pools.d.ts +4 -4
- package/dist/lifecycle-pools.js +1 -1
- package/dist/merge-question-surfacer.d.ts +3 -3
- package/dist/merge-question-surfacer.js +2 -2
- package/dist/merge-question-surfacer.js.map +1 -1
- package/dist/mint-adr.js +4 -4
- package/dist/mirror-pool-scan.d.ts +2 -2
- package/dist/mirror-pool-scan.js +3 -3
- package/dist/mirror-pool-scan.js.map +1 -1
- package/dist/needs-attention.d.ts +13 -13
- package/dist/needs-attention.d.ts.map +1 -1
- package/dist/needs-attention.js +11 -11
- package/dist/needs-attention.js.map +1 -1
- package/dist/orphan-sidecar.d.ts +2 -2
- package/dist/placement.d.ts +6 -6
- package/dist/placement.js +2 -2
- package/dist/prompt.d.ts +16 -19
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +17 -19
- package/dist/prompt.js.map +1 -1
- package/dist/readiness.d.ts +1 -1
- package/dist/recover-isolated.js +1 -1
- package/dist/repo-config.js +12 -12
- package/dist/repo-config.js.map +1 -1
- package/dist/review-gate.d.ts +3 -3
- package/dist/review-gate.d.ts.map +1 -1
- package/dist/review-gate.js +11 -10
- package/dist/review-gate.js.map +1 -1
- package/dist/review-verdict.d.ts +2 -2
- package/dist/review-verdict.d.ts.map +1 -1
- package/dist/review-verdict.js +1 -1
- package/dist/run.d.ts +1 -1
- package/dist/run.js +4 -4
- package/dist/run.js.map +1 -1
- package/dist/scan.d.ts +10 -10
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +8 -8
- package/dist/scan.js.map +1 -1
- package/dist/select-order.d.ts +1 -1
- package/dist/select-priority.d.ts +12 -12
- package/dist/select-priority.d.ts.map +1 -1
- package/dist/select-priority.js +5 -5
- package/dist/select-priority.js.map +1 -1
- package/dist/sidecar.d.ts +2 -2
- package/dist/sidecar.js +2 -2
- package/dist/sidecar.js.map +1 -1
- package/dist/slug-namespace.d.ts +1 -1
- package/dist/slug-namespace.js +3 -3
- package/dist/slug-namespace.js.map +1 -1
- package/dist/spec-complete.js +2 -2
- package/dist/spec-complete.js.map +1 -1
- package/dist/start.d.ts +1 -1
- package/dist/start.js +3 -3
- package/dist/start.js.map +1 -1
- package/dist/status.d.ts +3 -3
- package/dist/status.js +4 -4
- package/dist/status.js.map +1 -1
- package/dist/surface-gate.d.ts +2 -2
- package/dist/surface-gate.d.ts.map +1 -1
- package/dist/surface-persist.d.ts +2 -2
- package/dist/surface-persist.d.ts.map +1 -1
- package/dist/tasker-review-loop.d.ts +8 -8
- package/dist/tasker-review-loop.d.ts.map +1 -1
- package/dist/tasker-review-loop.js +8 -8
- package/dist/tasker-review-loop.js.map +1 -1
- package/dist/tasking-eligibility.d.ts +21 -21
- package/dist/tasking-eligibility.d.ts.map +1 -1
- package/dist/tasking-eligibility.js +10 -10
- package/dist/tasking-lock.d.ts +8 -8
- package/dist/tasking-lock.d.ts.map +1 -1
- package/dist/tasking-lock.js +20 -21
- package/dist/tasking-lock.js.map +1 -1
- package/dist/tasking.d.ts +33 -33
- package/dist/tasking.d.ts.map +1 -1
- package/dist/tasking.js +88 -86
- package/dist/tasking.js.map +1 -1
- package/dist/triage-gate.d.ts +1 -1
- package/dist/triage-persist.d.ts +5 -5
- package/dist/triage-persist.js +15 -15
- package/dist/triage-persist.js.map +1 -1
- package/dist/verify-workflow-template.d.ts +1 -1
- package/dist/verify-workflow-template.js +2 -2
- package/dist/work-layout.d.ts +9 -7
- package/dist/work-layout.d.ts.map +1 -1
- package/dist/work-layout.js +9 -7
- package/dist/work-layout.js.map +1 -1
- package/dist/workspace.d.ts +1 -1
- package/package.json +1 -1
- package/src/advance-ci-template.ts +4 -4
- package/src/advance-classify.ts +5 -5
- package/src/advance-drivers.ts +10 -10
- package/src/advance-isolated.ts +3 -3
- package/src/advance-lifecycle-template.ts +9 -9
- package/src/advance-loop-driver.ts +3 -3
- package/src/advance-treeless-publish.ts +1 -1
- package/src/advance.ts +30 -30
- package/src/advancing-lock.ts +6 -6
- package/src/apply-decide.ts +2 -2
- package/src/apply-merge-action.ts +5 -5
- package/src/apply-persist.ts +8 -8
- package/src/buildable-body.ts +14 -14
- package/src/claim-cas.ts +4 -4
- package/src/cli.ts +83 -83
- package/src/close-job-template.ts +8 -8
- package/src/close-job.ts +26 -26
- package/src/complete.ts +11 -11
- package/src/concurrency.ts +1 -1
- package/src/config.ts +37 -37
- package/src/continue-branch.ts +1 -1
- package/src/cwd-section.ts +1 -1
- package/src/decision-engine.ts +3 -3
- package/src/do-autopick.ts +9 -9
- package/src/do-config.ts +6 -6
- package/src/do-remote-auto.ts +2 -2
- package/src/do.ts +47 -47
- package/src/drop-source.ts +2 -2
- package/src/env-config.ts +8 -8
- package/src/format.ts +3 -3
- package/src/frontmatter.ts +23 -33
- package/src/install-ci-branch-protection.ts +1 -1
- package/src/install-ci-capabilities/advance-lifecycle.ts +1 -1
- package/src/install-ci-capabilities/close-job.ts +1 -1
- package/src/install-ci-capabilities/example-noop.ts +1 -1
- package/src/install-ci-capabilities/intake.ts +2 -2
- package/src/install-ci-capabilities/verify.ts +1 -1
- package/src/install-ci-core.ts +4 -4
- package/src/install-ci-github.ts +1 -1
- package/src/install-ci.ts +4 -4
- package/src/intake-event.ts +6 -6
- package/src/intake-marker.ts +3 -3
- package/src/intake-triage.ts +2 -2
- package/src/intake-trigger-template.ts +17 -17
- package/src/intake.ts +97 -97
- package/src/integration-core.ts +35 -35
- package/src/isolation.ts +3 -3
- package/src/issue-provider.ts +4 -4
- package/src/item-lock.ts +21 -21
- package/src/item-path.ts +2 -2
- package/src/ledger-lint.ts +9 -9
- package/src/ledger-read.ts +81 -81
- package/src/ledger-write.ts +3 -3
- package/src/lifecycle-gather.ts +16 -16
- package/src/lifecycle-pools.ts +4 -4
- package/src/merge-question-surfacer.ts +4 -4
- package/src/mint-adr.ts +4 -4
- package/src/mirror-pool-scan.ts +5 -5
- package/src/needs-attention.ts +22 -22
- package/src/orphan-sidecar.ts +2 -2
- package/src/placement.ts +6 -6
- package/src/prompt.ts +20 -25
- package/src/readiness.ts +1 -1
- package/src/recover-isolated.ts +1 -1
- package/src/repo-config.ts +12 -12
- package/src/review-gate.ts +12 -11
- package/src/review-verdict.ts +2 -2
- package/src/run.ts +5 -5
- package/src/scan.ts +15 -15
- package/src/select-order.ts +1 -1
- package/src/select-priority.ts +13 -13
- package/src/sidecar.ts +3 -3
- package/src/slug-namespace.ts +3 -3
- package/src/spec-complete.ts +2 -2
- package/src/start.ts +4 -4
- package/src/status.ts +7 -7
- package/src/surface-gate.ts +2 -2
- package/src/surface-persist.ts +2 -2
- package/src/tasker-review-loop.ts +15 -15
- package/src/tasking-eligibility.ts +21 -21
- package/src/tasking-lock.ts +27 -28
- package/src/tasking.ts +123 -121
- package/src/triage-gate.ts +1 -1
- package/src/triage-persist.ts +16 -16
- package/src/verify-workflow-template.ts +2 -2
- package/src/work-layout.ts +9 -7
- package/src/workspace.ts +1 -1
package/src/scan.ts
CHANGED
|
@@ -53,7 +53,7 @@ export function lifecycleGatesFrom(config: {
|
|
|
53
53
|
surfaceBlockers: boolean;
|
|
54
54
|
/**
|
|
55
55
|
* Spec `staging-surface-and-apply-promote-safety` F2 — the gate that widens
|
|
56
|
-
* the SURFACE candidate set into STAGING (`tasks/backlog/` + `
|
|
56
|
+
* the SURFACE candidate set into STAGING (`tasks/backlog/` + `specs/proposed/`).
|
|
57
57
|
* Threaded here so the `scan --json` `lifecycle.surface[]` reflects the
|
|
58
58
|
* expanded pool and the CI matrix enumerates staging surface legs. BUILD/claim
|
|
59
59
|
* stays pool-only — only this lifecycle path widens.
|
|
@@ -78,7 +78,7 @@ export interface ScannedTriageItem {
|
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
80
|
* A surface/apply lifecycle item, with its namespace. SURFACE only ever carries
|
|
81
|
-
* `needsAnswers` task/
|
|
81
|
+
* `needsAnswers` task/spec items (an observation with no sidecar goes to `triage`,
|
|
82
82
|
* not `surface`). APPLY, however, ALSO carries an ANSWERED OBSERVATION: since the
|
|
83
83
|
* classifier (`buildLifecyclePools`) routes an observation whose sidecar is
|
|
84
84
|
* all-answered to `apply` (CONSUME, always-on), the projection MUST keep it here
|
|
@@ -108,7 +108,7 @@ export interface ScannedBlockedItem {
|
|
|
108
108
|
export interface ScannedLifecycle {
|
|
109
109
|
/** Untriaged observations → `obs:<slug>` legs (gated by `observationTriage`). */
|
|
110
110
|
triage: ScannedTriageItem[];
|
|
111
|
-
/** `needsAnswers` task/
|
|
111
|
+
/** `needsAnswers` task/spec items with no answered sidecar → surface legs (gated by `surfaceBlockers`). */
|
|
112
112
|
surface: ScannedBlockedItem[];
|
|
113
113
|
/**
|
|
114
114
|
* Items WITH an all-answered sidecar → apply legs (CONSUME, always-on). Carries
|
|
@@ -132,7 +132,7 @@ export interface ScannedItem extends ReadyItem {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
* A
|
|
135
|
+
* A SPEC entry in `scan --json`'s taskable-spec pool — the SAME shape an eligible
|
|
136
136
|
* task carries in `items[]` (a `slug` + an `eligibility.eligible` boolean), so
|
|
137
137
|
* the propose-matrix `jq` filter mirrors the task one: `select(.eligibility.eligible)
|
|
138
138
|
* | "spec:" + .slug`. "Eligible" here means TASKABLE — the per-repo `autoTask`
|
|
@@ -159,7 +159,7 @@ export interface RepoReport {
|
|
|
159
159
|
items: ScannedItem[];
|
|
160
160
|
/**
|
|
161
161
|
* The TASKABLE-SPEC pool for this repo (the `specs[]` companion of `items[]`):
|
|
162
|
-
* every spec in `work/
|
|
162
|
+
* every spec in `work/specs/ready/` not already in `work/specs/tasked/`, each tagged with
|
|
163
163
|
* `eligibility.eligible` from {@link taskableSpecs} (the SAME `autoslice-gate`
|
|
164
164
|
* predicate the mirror-side pool scan uses — NOT a forked predicate). This is
|
|
165
165
|
* what makes the propose-mode CI matrix enumerate `spec:<slug>` legs for ready
|
|
@@ -183,7 +183,7 @@ export interface RepoReport {
|
|
|
183
183
|
*/
|
|
184
184
|
lifecycle: ScannedLifecycle;
|
|
185
185
|
/**
|
|
186
|
-
* The one-slug-one-folder LINT result (
|
|
186
|
+
* The one-slug-one-folder LINT result (spec `ledger-integrity` story 3): any
|
|
187
187
|
* slug present in MORE THAN ONE `work/` status folder in THIS repo's ledger.
|
|
188
188
|
* Empty ⇒ a clean ledger. Non-empty ⇒ a corrupt ledger the formatter WARNS
|
|
189
189
|
* about loudly and a human must resolve (never auto-fixed). Derived by listing
|
|
@@ -191,7 +191,7 @@ export interface RepoReport {
|
|
|
191
191
|
*/
|
|
192
192
|
ledgerDuplicates: DuplicateSlug[];
|
|
193
193
|
/**
|
|
194
|
-
* The PER-ITEM LOCK in-flight view for this repo (
|
|
194
|
+
* The PER-ITEM LOCK in-flight view for this repo (spec
|
|
195
195
|
* `ledger-status-per-item-lock-refs` US #8; task
|
|
196
196
|
* `needs-attention-as-stuck-lock-state`): the held lock entries read from the
|
|
197
197
|
* repo's `refs/dorfl/lock/*` refs — `active` holds (in-progress) and
|
|
@@ -240,7 +240,7 @@ export function readReadyItems(repoPath: string): ReadyItem[] {
|
|
|
240
240
|
* through the EXACT same eligibility path as in-place (`do-autopick`), not a fork.
|
|
241
241
|
*/
|
|
242
242
|
/**
|
|
243
|
-
* Score a
|
|
243
|
+
* Score a spec pool down to its TASKABLE subset, then label every spec with
|
|
244
244
|
* `eligibility.eligible` (true ⇔ taskable). REUSES {@link taskableSpecs} —
|
|
245
245
|
* the SAME `autoslice-gate` predicate the mirror-side `scanMirrorPool` + the
|
|
246
246
|
* in-place `do-autopick` pool already run — so what is taskable does not
|
|
@@ -281,7 +281,7 @@ export function scoreSpecs(
|
|
|
281
281
|
*
|
|
282
282
|
* The pool items' `namespace` is the wider {@link SelectedNamespace}. SURFACE by
|
|
283
283
|
* construction only carries `'task'`/`'prd'` (an observation with no sidecar is a
|
|
284
|
-
* `triage` candidate, never `surface`), so it narrows + drops any non-task/
|
|
284
|
+
* `triage` candidate, never `surface`), so it narrows + drops any non-task/spec
|
|
285
285
|
* defensively. APPLY additionally admits `'observation'` (an answered observation
|
|
286
286
|
* sidecar → apply), and it MUST be kept so the matrix `jq` emits its
|
|
287
287
|
* `observation:<slug>` apply leg — narrowing it away here is exactly what stranded
|
|
@@ -324,7 +324,7 @@ export function scoreItems(
|
|
|
324
324
|
counts: {totalItems: number; totalEligible: number},
|
|
325
325
|
heldSlugs: Set<string> = new Set(),
|
|
326
326
|
): ScannedItem[] {
|
|
327
|
-
// HELD-SLUG SUBTRACTION (
|
|
327
|
+
// HELD-SLUG SUBTRACTION (spec `ledger-status-per-item-lock-refs` US #15; task
|
|
328
328
|
// `claim-acquires-unified-lock-no-body-move`): exclude any pool slug whose
|
|
329
329
|
// per-item lock is currently held — the eligible pool is "in `tasks/ready/` on
|
|
330
330
|
// `main` AND no lock held".
|
|
@@ -435,7 +435,7 @@ export async function scan(
|
|
|
435
435
|
// the lock refs from the mirror's origin; non-fatal (empty set on any fault),
|
|
436
436
|
// so the read-only scan degrades gracefully exactly as its config reads do.
|
|
437
437
|
const heldSlugs = await heldTaskSlugs(mirror.path, 'origin', options.env);
|
|
438
|
-
// The PER-ITEM LOCK in-flight view (
|
|
438
|
+
// The PER-ITEM LOCK in-flight view (spec US #8; task
|
|
439
439
|
// `needs-attention-as-stuck-lock-state`): ADDITIONALLY read the full held
|
|
440
440
|
// lock entries (action × state + reason) from the mirror's lock refs, so the
|
|
441
441
|
// scan surfaces held (in-progress) + stuck (needs-attention) items. Read from
|
|
@@ -448,7 +448,7 @@ export async function scan(
|
|
|
448
448
|
'origin',
|
|
449
449
|
options.env,
|
|
450
450
|
);
|
|
451
|
-
// Spec pool — the TASKABLE-
|
|
451
|
+
// Spec pool — the TASKABLE-SPEC companion of the task pool above
|
|
452
452
|
// (`ci-propose-matrix-must-enumerate-sliceable-prds-not-only-slices`). Resolve
|
|
453
453
|
// `autoTask` PER REPO from the mirror's COMMITTED `.dorfl.json`
|
|
454
454
|
// (exactly as the mirror-side pool scan does — NOT forked); a read fault is
|
|
@@ -508,7 +508,7 @@ export async function scan(
|
|
|
508
508
|
env: options.env,
|
|
509
509
|
}),
|
|
510
510
|
);
|
|
511
|
-
// The one-slug-one-folder LINT (
|
|
511
|
+
// The one-slug-one-folder LINT (spec story 3): derive any slug residing in >1
|
|
512
512
|
// status folder from the mirror's committed `main` tree (the SAME `ls-tree`
|
|
513
513
|
// read the seam uses), so a corrupt ledger is surfaced LOUDLY by the formatter.
|
|
514
514
|
const ledgerDuplicates = lintRefLedger('main', mirror.path, options.env);
|
|
@@ -543,7 +543,7 @@ export function scanRepoPaths(
|
|
|
543
543
|
repoPaths: string[],
|
|
544
544
|
config: Config,
|
|
545
545
|
/**
|
|
546
|
-
* The HELD-SLUG set to SUBTRACT from each repo's pool (`tasks/ready/`) (
|
|
546
|
+
* The HELD-SLUG set to SUBTRACT from each repo's pool (`tasks/ready/`) (spec
|
|
547
547
|
* `ledger-status-per-item-lock-refs` US #15). This is a WORKING-TREE, OFFLINE
|
|
548
548
|
* scan (it has no arbiter handle to fetch the lock refs from — that is the
|
|
549
549
|
* registry `scan`'s job), so the held set is supplied by the in-place CALLER
|
|
@@ -569,7 +569,7 @@ export function scanRepoPaths(
|
|
|
569
569
|
global: config,
|
|
570
570
|
override,
|
|
571
571
|
}).config;
|
|
572
|
-
// Spec pool — the TASKABLE-
|
|
572
|
+
// Spec pool — the TASKABLE-SPEC companion of the task pool. Resolve
|
|
573
573
|
// `autoTask` PER REPO from the working-tree `.dorfl.json` (the same
|
|
574
574
|
// way `autoBuild` is resolved); `taskableSpecs` (the SAME `autoslice-gate`
|
|
575
575
|
// predicate the autopick paths run) decides what is taskable — no forked
|
package/src/select-order.ts
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* member of this union and naming it is a usage error.
|
|
29
29
|
*
|
|
30
30
|
* - `build` — build an eligible task;
|
|
31
|
-
* - `task` — task a taskable
|
|
31
|
+
* - `task` — task a taskable spec;
|
|
32
32
|
* - `surface` — render a `needsAnswers` blocker into an answerable sidecar;
|
|
33
33
|
* - `triage` — triage an untriaged observation.
|
|
34
34
|
*/
|
package/src/select-priority.ts
CHANGED
|
@@ -30,16 +30,16 @@ import {
|
|
|
30
30
|
* land). Build it standalone; do not assume `run` already calls it.
|
|
31
31
|
*
|
|
32
32
|
* **Up to FIVE pools.** The `scan`/`selectCandidates`/eligibility model is
|
|
33
|
-
* TASK-ONLY (there is no
|
|
33
|
+
* TASK-ONLY (there is no spec candidate). So this helper composes:
|
|
34
34
|
*
|
|
35
35
|
* - the **`build` pool** (eligible TASKS) — the EXISTING {@link selectCandidates}
|
|
36
36
|
* path (round-robin across repos, capped). This is the EXACT task-selection
|
|
37
37
|
* primitive `run` uses, so `run` and this helper SHARE it (they share
|
|
38
38
|
* `selectCandidates`, the task-pool core).
|
|
39
|
-
* - the **`task` pool** (
|
|
39
|
+
* - the **`task` pool** (spec-to-task) — a pool the caller builds from the spec reader
|
|
40
40
|
* (`ledgerRead.resolveSpecPool`) filtered by `autoslice-gate`'s pure predicate
|
|
41
41
|
* ({@link resolveTaskingEligibility}); see {@link taskableSpecs}. The helper
|
|
42
|
-
* does NOT reinvent
|
|
42
|
+
* does NOT reinvent spec eligibility.
|
|
43
43
|
*
|
|
44
44
|
* `do` is STRICTLY SEQUENTIAL (parallelism is `run`'s job, ADR §3) — this helper
|
|
45
45
|
* only ORDERS + COUNTS the items; the caller runs the existing `do` pipeline per
|
|
@@ -82,7 +82,7 @@ export interface SelectedItem {
|
|
|
82
82
|
*/
|
|
83
83
|
export type LifecycleSelectedItem = SelectedItem;
|
|
84
84
|
|
|
85
|
-
/** A
|
|
85
|
+
/** A spec candidate for the tasking pool, before the eligibility gate runs. */
|
|
86
86
|
export interface SpecCandidate {
|
|
87
87
|
repoPath: string;
|
|
88
88
|
slug: string;
|
|
@@ -91,21 +91,21 @@ export interface SpecCandidate {
|
|
|
91
91
|
taskedAfter: string[];
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/** Inputs to {@link taskableSpecs}: the raw
|
|
94
|
+
/** Inputs to {@link taskableSpecs}: the raw spec pool + the gate context. */
|
|
95
95
|
export interface TaskableSpecsInput {
|
|
96
|
-
/** Every
|
|
96
|
+
/** Every spec enumerated from `work/specs/ready/` (the auto-task candidate source). */
|
|
97
97
|
candidates: SpecCandidate[];
|
|
98
|
-
/** Slugs whose
|
|
98
|
+
/** Slugs whose spec resides in `work/specs/tasked/` (resolves `taskedAfter`). */
|
|
99
99
|
taskedSlugs: Set<string>;
|
|
100
100
|
/** The repo's resolved `autoTask` policy (`autoslice-gate`'s per-repo key). */
|
|
101
101
|
autoTask: boolean;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
|
-
* Filter a raw
|
|
105
|
+
* Filter a raw spec pool down to the TASKABLE prds, in declaration order, using
|
|
106
106
|
* `autoslice-gate`'s pure predicate ({@link resolveTaskingEligibility}) — NOT a
|
|
107
|
-
* reinvented eligibility model. A
|
|
108
|
-
* humanOnly !== true && autoTask` AND every `taskedAfter`
|
|
107
|
+
* reinvented eligibility model. A spec is taskable iff `needsAnswers !== true &&
|
|
108
|
+
* humanOnly !== true && autoTask` AND every `taskedAfter` spec is already tasked.
|
|
109
109
|
* Pure: no I/O (the caller reads the pool through `ledgerRead.resolveSpecPool`).
|
|
110
110
|
*/
|
|
111
111
|
export function taskableSpecs(input: TaskableSpecsInput): SpecCandidate[] {
|
|
@@ -171,7 +171,7 @@ export interface SelectPrioritisedInput {
|
|
|
171
171
|
*/
|
|
172
172
|
lifecycle?: SelectedLifecyclePools;
|
|
173
173
|
/**
|
|
174
|
-
* The HELD-SLUG set to SUBTRACT from the `build` pool (eligible TASKS) —
|
|
174
|
+
* The HELD-SLUG set to SUBTRACT from the `build` pool (eligible TASKS) — spec
|
|
175
175
|
* `ledger-status-per-item-lock-refs` US #15, task
|
|
176
176
|
* `claim-acquires-unified-lock-no-body-move`. A task whose per-item lock is
|
|
177
177
|
* currently held is dropped from selection, so the eligible pool is "in
|
|
@@ -198,7 +198,7 @@ export interface SelectedLifecyclePools {
|
|
|
198
198
|
* Build the ordered, counted list of items to do across the (up to) FIVE pools,
|
|
199
199
|
* applying the configurable {@link selectionOrder} with `apply` PINNED FIRST and
|
|
200
200
|
* the count bound. The task pool is selected via the EXISTING
|
|
201
|
-
* {@link selectCandidates} (the shared primitive `run` uses); the
|
|
201
|
+
* {@link selectCandidates} (the shared primitive `run` uses); the spec pool is the
|
|
202
202
|
* pre-filtered {@link taskableSpecs} output; the lifecycle pools (`apply` /
|
|
203
203
|
* `surface` / `triage`) are caller-built (none for `do`).
|
|
204
204
|
*
|
|
@@ -235,7 +235,7 @@ export function selectPrioritised(
|
|
|
235
235
|
|
|
236
236
|
// The per-pool item lists, keyed by the orderable pool name. NOTE the
|
|
237
237
|
// vocabulary bridge: `build` = the eligible-TASK pool (namespace `task`),
|
|
238
|
-
// `task` = the taskable-
|
|
238
|
+
// `task` = the taskable-spec pool (namespace `prd`) — the action names, not the
|
|
239
239
|
// item namespaces (task `advance-selection-order-config`).
|
|
240
240
|
const byPool: Record<SelectionPool, SelectedItem[]> = {
|
|
241
241
|
build: buildItems,
|
package/src/sidecar.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {parseSlugArg, type SlugNamespace} from './slug-namespace.js';
|
|
|
2
2
|
import {workItemRel} from './work-layout.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* The **question/answer SIDECAR contract** (
|
|
5
|
+
* The **question/answer SIDECAR contract** (spec `advance-loop`, task
|
|
6
6
|
* `advance-sidecar-contract`) — the one genuinely-new piece of the `advance`
|
|
7
7
|
* family. A strict, tooling-OWNED per-item file `work/questions/<type>-<slug>.md`
|
|
8
8
|
* carrying per-entry answered-state, so the tooling fully owns the Q&A artifact
|
|
@@ -208,7 +208,7 @@ function typeForNamespace(
|
|
|
208
208
|
if (explicit === 'task') {
|
|
209
209
|
return 'task';
|
|
210
210
|
}
|
|
211
|
-
// `parseSlugArg` only knows `task:`/`
|
|
211
|
+
// `parseSlugArg` only knows `task:`/`spec:`; the sidecar adds the
|
|
212
212
|
// `observation:` namespace (`obs:` is the CLI alias the verb resolves; the
|
|
213
213
|
// sidecar stores the canonical `observation`). A bare slug (no prefix)
|
|
214
214
|
// defaults to the task namespace, matching the resolver's "bare = task".
|
|
@@ -267,7 +267,7 @@ export function sidecarPathFor(identity: string): string {
|
|
|
267
267
|
* canonical {@link sidecarPathFor} path FIRST, then any legacy-data fallback that
|
|
268
268
|
* may still be on disk before the migration command converts it.
|
|
269
269
|
*
|
|
270
|
-
* MIGRATE step (
|
|
270
|
+
* MIGRATE step (spec `prd-to-spec-vocabulary-cutover-and-migration-command`): the
|
|
271
271
|
* producer side now emits `spec:<slug>`, so {@link sidecarPathFor} resolves
|
|
272
272
|
* `work/questions/spec-<slug>.md`. But the ON-DISK sidecar is still the legacy
|
|
273
273
|
* `work/questions/prd-<slug>.md` until `dorfl prd-to-spec` renames the DATA. So a
|
package/src/slug-namespace.ts
CHANGED
|
@@ -263,7 +263,7 @@ export function resolveSlug(input: ResolveSlugInput): ResolvedSlug {
|
|
|
263
263
|
const parsed = parseSlugArg(input.arg);
|
|
264
264
|
|
|
265
265
|
if (parsed.explicit === 'observation') {
|
|
266
|
-
// `do` spans the task/
|
|
266
|
+
// `do` spans the task/spec namespaces ONLY (build a task OR task a spec).
|
|
267
267
|
// The `observation` namespace is `advance`'s alone (triage). Reject it here
|
|
268
268
|
// rather than let a `do obs:<slug>` resolve into a namespace `do` cannot act
|
|
269
269
|
// on — point the human at the verb that owns it.
|
|
@@ -289,7 +289,7 @@ export function resolveSlug(input: ResolveSlugInput): ResolvedSlug {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
/**
|
|
292
|
-
* Resolve a slug argument for the `advance` verb (
|
|
292
|
+
* Resolve a slug argument for the `advance` verb (spec `advance-loop`, task
|
|
293
293
|
* `advance-verb-resolver`). `advance` is the SIBLING top-level verb (NOT a `do`
|
|
294
294
|
* subcommand) that reuses this SAME shared `prefix:arg` resolver, EXTENDED with
|
|
295
295
|
* the `observation` namespace `do` does not span:
|
|
@@ -362,6 +362,6 @@ export function resolveTaskOnlyArg(arg: string): string {
|
|
|
362
362
|
);
|
|
363
363
|
}
|
|
364
364
|
// Bare or `task:` → the task slug. (A bare slug on a task-only command is
|
|
365
|
-
// unambiguously the task; the
|
|
365
|
+
// unambiguously the task; the spec namespace is unreachable here.)
|
|
366
366
|
return parsed.slug;
|
|
367
367
|
}
|
package/src/spec-complete.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from './work-layout.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* The read-only **"is this spec complete?"** core query (
|
|
13
|
+
* The read-only **"is this spec complete?"** core query (spec `issue-intake`, US #8 —
|
|
14
14
|
* the closure-linkage half). Given a spec slug + a `work/` tree, a spec is COMPLETE
|
|
15
15
|
* iff there is **≥1 task carrying `spec:<slug>`** AND **all such tasks reside in
|
|
16
16
|
* `work/done/`**. Pure `work/`-folder logic — no seam, no git, no `gh`, no mutation.
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
* means the spec is not yet complete.
|
|
33
33
|
*/
|
|
34
34
|
|
|
35
|
-
/** The task lifecycle folders a `
|
|
35
|
+
/** The task lifecycle folders a `spec:<slug>` task can reside in. */
|
|
36
36
|
const TASK_FOLDERS = TASK_LIFECYCLE_FOLDERS;
|
|
37
37
|
|
|
38
38
|
/** Where a task resides — the folder name under `work/`. */
|
package/src/start.ts
CHANGED
|
@@ -78,7 +78,7 @@ export interface StartOptions {
|
|
|
78
78
|
*/
|
|
79
79
|
override?: boolean;
|
|
80
80
|
/**
|
|
81
|
-
* `--allow-backlog` (
|
|
81
|
+
* `--allow-backlog` (spec
|
|
82
82
|
* `do-allow-backlog-drive-staged-tasks-without-promotion`): recognise a
|
|
83
83
|
* `tasks/backlog/`-resident body (staging) as a valid start/onboard residence,
|
|
84
84
|
* so the no-checkout `do --remote/--isolated … --allow-backlog` flow (which
|
|
@@ -236,7 +236,7 @@ async function runStart(
|
|
|
236
236
|
* resume the lock `stuck → active`, onboard).
|
|
237
237
|
* Everything else dispatches by folder unchanged.
|
|
238
238
|
*
|
|
239
|
-
* Under `--allow-backlog` (
|
|
239
|
+
* Under `--allow-backlog` (spec
|
|
240
240
|
* `do-allow-backlog-drive-staged-tasks-without-promotion`) a body resting in
|
|
241
241
|
* `tasks/backlog/` (staging) is treated EXACTLY like the pool for this re-key
|
|
242
242
|
* (held active ⇒ in-progress; held stuck ⇒ needs-attention; else the backlog
|
|
@@ -620,7 +620,7 @@ async function switchToWorkBranch(params: {
|
|
|
620
620
|
}): Promise<SwitchResult> {
|
|
621
621
|
const {slug, arbiter, cwd, env, note} = params;
|
|
622
622
|
// `start` is a TASK-only command: the branch is the task-namespaced
|
|
623
|
-
// `work/task-<slug>` (distinct from a same-slug
|
|
623
|
+
// `work/task-<slug>` (distinct from a same-slug spec-tasking branch).
|
|
624
624
|
const branch = workBranchRef('task', slug);
|
|
625
625
|
|
|
626
626
|
await gitHard(['fetch', '--quiet', arbiter], cwd, env);
|
|
@@ -909,7 +909,7 @@ async function inferSlugFromBranch(
|
|
|
909
909
|
|
|
910
910
|
/**
|
|
911
911
|
* Which work/ folder the slug currently lives in on `<arbiter>/main`. Under
|
|
912
|
-
* `--allow-backlog` (
|
|
912
|
+
* `--allow-backlog` (spec `do-allow-backlog-drive-staged-tasks-without-promotion`)
|
|
913
913
|
* it ALSO recognises `tasks/backlog/` (staging) at LOWEST priority — after the
|
|
914
914
|
* pool — so a same-slug pool copy still wins; otherwise staging is invisible.
|
|
915
915
|
*/
|
package/src/status.ts
CHANGED
|
@@ -81,7 +81,7 @@ export interface JobStatus {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* One repo's PER-ITEM LOCK refs, surfaced for the dashboard (
|
|
84
|
+
* One repo's PER-ITEM LOCK refs, surfaced for the dashboard (spec
|
|
85
85
|
* `ledger-status-per-item-lock-refs` US #8; task
|
|
86
86
|
* `needs-attention-as-stuck-lock-state`). The in-flight view read from the lock
|
|
87
87
|
* refs — held (`active` = in-progress) and stuck (`needs-attention`) entries +
|
|
@@ -111,7 +111,7 @@ export interface StatusReport {
|
|
|
111
111
|
/** Stuck (needs-attention), crashed (running-but-dead), or un-reaped (done) jobs. */
|
|
112
112
|
attention: JobStatus[];
|
|
113
113
|
/**
|
|
114
|
-
* The PER-ITEM LOCK in-flight view (
|
|
114
|
+
* The PER-ITEM LOCK in-flight view (spec `ledger-status-per-item-lock-refs` US
|
|
115
115
|
* #8; task `needs-attention-as-stuck-lock-state`): per registered hub mirror,
|
|
116
116
|
* the held lock entries read from the mirror's `refs/dorfl/lock/*` refs —
|
|
117
117
|
* `active` holds (in-progress) and `stuck` holds (needs-attention) + reasons.
|
|
@@ -124,7 +124,7 @@ export interface StatusReport {
|
|
|
124
124
|
*/
|
|
125
125
|
lockHeld?: RepoLockEntries[];
|
|
126
126
|
/**
|
|
127
|
-
* The one-slug-one-folder LINT (
|
|
127
|
+
* The one-slug-one-folder LINT (spec `ledger-integrity` story 3): per registered
|
|
128
128
|
* hub mirror, any slug present in MORE THAN ONE `work/` status folder (a corrupt
|
|
129
129
|
* ledger). Read from the mirror's bare `main` ref (the SAME `ls-tree` source the
|
|
130
130
|
* needs-attention surface uses). Only repos WITH a duplicate appear. `status`
|
|
@@ -235,7 +235,7 @@ export async function status(options: StatusOptions): Promise<StatusReport> {
|
|
|
235
235
|
// reflects the remote truth. Never fatal — a failed fetch WARNS and falls back
|
|
236
236
|
// to the mirror's last-known `main`.
|
|
237
237
|
fetchMirrorMainOrWarn({mirrorPath, warn: options.warn, env: options.env});
|
|
238
|
-
// The PER-ITEM LOCK in-flight view (
|
|
238
|
+
// The PER-ITEM LOCK in-flight view (spec US #8): read the mirror's lock refs to
|
|
239
239
|
// surface held (`active` = in-progress) and stuck (`needs-attention`) entries +
|
|
240
240
|
// reasons/questions. A bare hub mirror's arbiter is its `origin` (the SAME
|
|
241
241
|
// handle the `scan` held-slug subtraction reads). Best-effort: a fetch/read
|
|
@@ -249,7 +249,7 @@ export async function status(options: StatusOptions): Promise<StatusReport> {
|
|
|
249
249
|
if (entries.length > 0) {
|
|
250
250
|
lockHeld.push({repoPath: mirrorPath, entries});
|
|
251
251
|
}
|
|
252
|
-
// The one-slug-one-folder LINT (
|
|
252
|
+
// The one-slug-one-folder LINT (spec story 3): derive any slug residing in >1
|
|
253
253
|
// status folder from the SAME freshly-fetched `main` ref, surfaced LOUDLY.
|
|
254
254
|
const dups = lintRefLedger('main', mirrorPath, options.env);
|
|
255
255
|
if (dups.length > 0) {
|
|
@@ -359,7 +359,7 @@ export function formatStatus(report: StatusReport): string {
|
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
// The PER-ITEM LOCK in-flight view (
|
|
362
|
+
// The PER-ITEM LOCK in-flight view (spec US #8; task
|
|
363
363
|
// `cutover-needs-attention-becomes-lock-stuck-recovery-surface`): the held lock
|
|
364
364
|
// refs read from each mirror — `active` holds (in-progress) and `stuck` holds
|
|
365
365
|
// (needs-attention) + their reasons/questions. This is the SOLE stuck-state
|
|
@@ -377,7 +377,7 @@ export function formatStatus(report: StatusReport): string {
|
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
-
// The one-slug-one-folder LINT (
|
|
380
|
+
// The one-slug-one-folder LINT (spec `ledger-integrity` story 3): WARN LOUDLY
|
|
381
381
|
// about every slug residing in >1 status folder of a registered mirror's ledger
|
|
382
382
|
// (a corrupt ledger — never a silent pass). A human must resolve each.
|
|
383
383
|
if (dupCount > 0) {
|
package/src/surface-gate.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {parseableJsonContractPrompt} from './review-verdict.js';
|
|
|
6
6
|
import type {NewQuestion} from './sidecar.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* The **SURFACE gate** (
|
|
9
|
+
* The **SURFACE gate** (spec `advance-loop`, task `advance-rung-surface`,
|
|
10
10
|
* US #32/33) — the surface-question rung's fresh-context spawn, the DIRECT mirror
|
|
11
11
|
* of the PR/code review gate ({@link import('./review-gate.js')}). On
|
|
12
12
|
* `classify=surface`, the advance engine spawns a FRESH-CONTEXT agent with the
|
|
@@ -70,7 +70,7 @@ export interface SurfaceEmit {
|
|
|
70
70
|
|
|
71
71
|
/** What the surface gate needs to launch a fresh-context surface of one item. */
|
|
72
72
|
export interface SurfaceGateInput {
|
|
73
|
-
/** The namespaced identity the surface is for (`task:foo` / `
|
|
73
|
+
/** The namespaced identity the surface is for (`task:foo` / `spec:bar` / `observation:baz`). */
|
|
74
74
|
item: string;
|
|
75
75
|
/** The working clone/checkout the gate runs in. */
|
|
76
76
|
cwd: string;
|
package/src/surface-persist.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from './sidecar.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* The engine-owned SURFACE PERSIST (
|
|
16
|
+
* The engine-owned SURFACE PERSIST (spec `advance-loop`, task
|
|
17
17
|
* `advance-rung-surface`, US #15/33) — the half of the surface rung the ENGINE
|
|
18
18
|
* owns (the skill JUDGES, the engine PERSISTS). Given the questions the
|
|
19
19
|
* `surface-questions` skill EMITTED (gathered by `surface-gate.ts`'s spawn), the
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
export interface SurfacePersistOptions {
|
|
54
54
|
/** Working clone/worktree the persist commits in. */
|
|
55
55
|
cwd: string;
|
|
56
|
-
/** The namespaced item identity (`task:foo` / `
|
|
56
|
+
/** The namespaced item identity (`task:foo` / `spec:bar` / `observation:baz`). */
|
|
57
57
|
item: string;
|
|
58
58
|
/**
|
|
59
59
|
* The item file path RELATIVE to `cwd` (e.g. `work/backlog/foo.md`). The
|
|
@@ -29,9 +29,9 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* **The tasker review→edit→re-review→converge LOOP** (`slicer-review-edit-loop`,
|
|
32
|
-
* GATES
|
|
32
|
+
* GATES spec `work/specs/ready/review.md` RESOLVED DESIGN — Shape 2 / insertion point A).
|
|
33
33
|
*
|
|
34
|
-
* On the `do
|
|
34
|
+
* On the `do spec:<slug>` tasking path (`tasking.ts`/`performTask`), AFTER the
|
|
35
35
|
* agent produces a candidate set of `work/tasks/backlog/<slug>.md` tasks and BEFORE the
|
|
36
36
|
* runner finalises/lands them, this loop RUNS the `review` SKILL
|
|
37
37
|
* (`skills/review/SKILL.md`), APPLIES its findings as EDITS to the candidate task
|
|
@@ -47,7 +47,7 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
47
47
|
* N so the loop can never run forever.
|
|
48
48
|
*
|
|
49
49
|
* ⚠️ ASPIRATION-VS-BUILT (2026-06-10): the "single context" wording above is the
|
|
50
|
-
*
|
|
50
|
+
* spec's ASPIRATION, NOT what this module does at runtime. The ACTUAL N loop is
|
|
51
51
|
* RUNNER-DRIVEN and PER-PASS: `runOneExecution` does `for (pass …) { gate(…);
|
|
52
52
|
* applyEdits(…to disk…) }` — ONE agent LAUNCH per pass, the runner writing the
|
|
53
53
|
* agent's edits to the candidate task FILES (`work/tasks/backlog/`) between passes, the
|
|
@@ -75,7 +75,7 @@ export {parseReviewVerdict as parseTaskReviewVerdict} from './review-verdict.js'
|
|
|
75
75
|
* - **a specific uncertain task** → emit it `needsAnswers: true` with the
|
|
76
76
|
* questions in its body (created, not agent-buildable until a human answers).
|
|
77
77
|
* - **the whole decomposition unclear / `taskerLoopMax` exhausted with blockers** →
|
|
78
|
-
* route the
|
|
78
|
+
* route the spec to `work/needs-attention/<slug>.md` with the questions as the
|
|
79
79
|
* reason, emitting NO guessed tasks.
|
|
80
80
|
*
|
|
81
81
|
* The verdict sink itself (the git transitions for those three outcomes) is the
|
|
@@ -101,7 +101,7 @@ export type TaskReviewVerdict = ReviewVerdict;
|
|
|
101
101
|
|
|
102
102
|
/** What the review gate needs to launch a fresh-context review+edit pass. */
|
|
103
103
|
export interface TaskReviewGateInput {
|
|
104
|
-
/** The
|
|
104
|
+
/** The spec slug whose candidate tasks are under review. */
|
|
105
105
|
slug: string;
|
|
106
106
|
/** The working clone/checkout the loop runs in (candidate tasks live here). */
|
|
107
107
|
cwd: string;
|
|
@@ -141,7 +141,7 @@ export type LoopOutcome =
|
|
|
141
141
|
| 'converged'
|
|
142
142
|
/** `taskerLoopMax` hit with blockers → specific uncertain task(s) → needsAnswers. */
|
|
143
143
|
| 'uncertain-tasks'
|
|
144
|
-
/** `taskerLoopMax` hit / decomposition unclear → route the
|
|
144
|
+
/** `taskerLoopMax` hit / decomposition unclear → route the spec to needs-attention. */
|
|
145
145
|
| 'decomposition-unclear';
|
|
146
146
|
|
|
147
147
|
/** The result of running the loop — the disposition the caller's sink routes. */
|
|
@@ -174,7 +174,7 @@ export interface RunTaskReviewLoopResult {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
export interface RunTaskReviewLoopOptions {
|
|
177
|
-
/** The
|
|
177
|
+
/** The spec slug whose candidate tasks are being improved. */
|
|
178
178
|
slug: string;
|
|
179
179
|
/** The working clone/checkout the loop runs in. */
|
|
180
180
|
cwd: string;
|
|
@@ -226,7 +226,7 @@ export interface RunTaskReviewLoopOptions {
|
|
|
226
226
|
* to the candidate task files, then re-review — until `verdict === 'approve'` (no
|
|
227
227
|
* NEW blocking issue → converged) or the pass count reaches `taskerLoopMax`. On the cap
|
|
228
228
|
* with a still-`block` verdict, ROUTE per the verdict's channels:
|
|
229
|
-
* - `decompositionUnclear` set ⇒ `decomposition-unclear` (
|
|
229
|
+
* - `decompositionUnclear` set ⇒ `decomposition-unclear` (spec → needs-attention,
|
|
230
230
|
* no guessed tasks);
|
|
231
231
|
* - else `uncertainTasks` (or, as a floor, every candidate task) ⇒
|
|
232
232
|
* `uncertain-tasks` (those tasks emitted `needsAnswers: true` + questions).
|
|
@@ -296,7 +296,7 @@ export async function runTaskReviewLoop(
|
|
|
296
296
|
note(
|
|
297
297
|
`Tasker review loop did not converge within taskerLoopMax=${taskerLoopMax} ` +
|
|
298
298
|
`across ${executions} fresh context(s); the whole decomposition is ` +
|
|
299
|
-
'unclear — routing the
|
|
299
|
+
'unclear — routing the spec to needs-attention (no guessed tasks).',
|
|
300
300
|
);
|
|
301
301
|
return {
|
|
302
302
|
outcome: 'decomposition-unclear',
|
|
@@ -308,7 +308,7 @@ export async function runTaskReviewLoop(
|
|
|
308
308
|
message:
|
|
309
309
|
`The decomposition of '${options.slug}' is still unclear after ` +
|
|
310
310
|
`taskerLoopMax=${taskerLoopMax} review pass(es) across ${executions} fresh ` +
|
|
311
|
-
'context(s); routing the
|
|
311
|
+
'context(s); routing the spec to needs-attention with the open ' +
|
|
312
312
|
'questions, emitting no guessed tasks.',
|
|
313
313
|
};
|
|
314
314
|
}
|
|
@@ -617,18 +617,18 @@ export function buildTaskReviewPrompt(input: TaskReviewGateInput): string {
|
|
|
617
617
|
const list = input.candidateTasks.map((p) => ` - ${p}`).join('\n');
|
|
618
618
|
return [
|
|
619
619
|
`You are a FRESH-CONTEXT reviewer in the TASKER review→edit→converge LOOP`,
|
|
620
|
-
`(insertion point A). Review the CANDIDATE TASKS just produced for the
|
|
620
|
+
`(insertion point A). Review the CANDIDATE TASKS just produced for the spec`,
|
|
621
621
|
`"${input.slug}":`,
|
|
622
622
|
list || ' (no candidate tasks found)',
|
|
623
623
|
``,
|
|
624
624
|
reviewDisciplinePrompt(),
|
|
625
625
|
``,
|
|
626
|
-
`Read the source
|
|
626
|
+
`Read the source spec (${workItemRel('specs-ready', `${input.slug}.md`)}) and review the candidate`,
|
|
627
627
|
`decomposition ADVERSARIALLY. Review the WHOLE SET — graph coherence / gaps /`,
|
|
628
628
|
`overlap / goal-composition (dependency-graph coherence, set-level gaps,`,
|
|
629
|
-
`overlapping/duplicated tasks, and "does the set compose into the
|
|
629
|
+
`overlapping/duplicated tasks, and "does the set compose into the spec goal")`,
|
|
630
630
|
`— not just per-task well-formedness. The DESTINATION CHECK ("if every task`,
|
|
631
|
-
`is built exactly as written, do we end up with the system the
|
|
631
|
+
`is built exactly as written, do we end up with the system the spec describes?")`,
|
|
632
632
|
`is PART OF this pass and may ITSELF trigger edits — that is why this is a`,
|
|
633
633
|
`loop, not a one-shot gate.`,
|
|
634
634
|
``,
|
|
@@ -645,7 +645,7 @@ export function buildTaskReviewPrompt(input: TaskReviewGateInput): string {
|
|
|
645
645
|
` can FIX a finding by editing (the natural improver step).`,
|
|
646
646
|
` - "uncertainTasks" — specific tasks you cannot make buildable (each gets`,
|
|
647
647
|
` \`needsAnswers: true\` with the questions in its body).`,
|
|
648
|
-
` - "decompositionUnclear" — the WHOLE decomposition is unsound (the
|
|
648
|
+
` - "decompositionUnclear" — the WHOLE decomposition is unsound (the spec is`,
|
|
649
649
|
` routed to needs-attention; emit no guessed tasks).`,
|
|
650
650
|
`Do NOT fill "review" / "edit" / "questions" — those are other callers'`,
|
|
651
651
|
`channels. Flag, do not guess: a flagged question costs one human glance; a`,
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure tasking-eligibility resolution — the auto-task decision layer, one level
|
|
3
|
-
* UP from the build gate (`eligibility.ts`). No I/O: callers pass in the
|
|
3
|
+
* UP from the build gate (`eligibility.ts`). No I/O: callers pass in the spec's
|
|
4
4
|
* two autonomy axes (`humanOnly`, `needsAnswers`), the repo's `autoTask` policy,
|
|
5
|
-
* the
|
|
6
|
-
* TASKED (resolved against `work/
|
|
5
|
+
* the spec's `taskedAfter` slugs, and the set of slugs whose prds are already
|
|
6
|
+
* TASKED (resolved against `work/specs/tasked/` residence, NOT `work/done/`).
|
|
7
7
|
*
|
|
8
8
|
* This mirrors the build-gate shape deliberately (CONTEXT.md / the `auto-slice`
|
|
9
|
-
*
|
|
10
|
-
* predicate, applied to a
|
|
11
|
-
* cross-
|
|
9
|
+
* spec): the same `needsAnswers !== true && humanOnly !== true && <repo policy>`
|
|
10
|
+
* predicate, applied to a spec's two axes + the repo's `autoTask` toggle — and a
|
|
11
|
+
* cross-spec ordering check that resolves against tasked-ness rather than done-ness.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type {HumanOnlyGate} from './eligibility.js';
|
|
15
15
|
|
|
16
16
|
export type {HumanOnlyGate};
|
|
17
17
|
|
|
18
|
-
/** Resolution of a
|
|
18
|
+
/** Resolution of a spec's `taskedAfter` against the set of already-tasked prds. */
|
|
19
19
|
export interface TaskedAfterResult {
|
|
20
|
-
/** True when every listed
|
|
20
|
+
/** True when every listed spec is already tasked. */
|
|
21
21
|
satisfied: boolean;
|
|
22
|
-
/** Listed
|
|
22
|
+
/** Listed spec slugs not yet tasked, in declaration order. */
|
|
23
23
|
missing: string[];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export interface TaskingEligibilityInput {
|
|
27
|
-
/** Autonomy axis 1 (DECIDED): a human must drive THIS
|
|
27
|
+
/** Autonomy axis 1 (DECIDED): a human must drive THIS spec's tasking. */
|
|
28
28
|
humanOnly: HumanOnlyGate;
|
|
29
|
-
/** Autonomy axis 2 (DISCOVERED): the
|
|
29
|
+
/** Autonomy axis 2 (DISCOVERED): the spec has unresolved questions. */
|
|
30
30
|
needsAnswers: HumanOnlyGate;
|
|
31
|
-
/** Cross-
|
|
31
|
+
/** Cross-spec order: spec slugs that must already be tasked before this one. */
|
|
32
32
|
taskedAfter: string[];
|
|
33
|
-
/** Slugs of prds that are already TASKED (residence in `work/
|
|
33
|
+
/** Slugs of prds that are already TASKED (residence in `work/specs/tasked/`). */
|
|
34
34
|
taskedSlugs: Set<string>;
|
|
35
35
|
/** Per-repo policy: may an agent auto-task *undeclared* prds in this repo? */
|
|
36
36
|
autoTask: boolean;
|
|
37
37
|
/**
|
|
38
|
-
* The target was named EXPLICITLY by the operator (`do
|
|
39
|
-
* `autoTask` POLICY is already satisfied — naming the
|
|
38
|
+
* The target was named EXPLICITLY by the operator (`do spec:<slug>`), so the
|
|
39
|
+
* `autoTask` POLICY is already satisfied — naming the spec IS the authorization,
|
|
40
40
|
* exactly as `do <task>` builds a named task regardless of `autoBuild` (the
|
|
41
41
|
* `autoBuild` precedent: the pool/scan gates the policy, the explicit claim path
|
|
42
42
|
* never re-checks it). When `true`, the policy term drops from the gate and ONLY
|
|
43
|
-
* the
|
|
43
|
+
* the spec's own readiness axes (`humanOnly`/`needsAnswers`) + `taskedAfter` bind.
|
|
44
44
|
* Defaults `false` (the AUTO-PICK pool path, where the `autoTask` policy DOES
|
|
45
45
|
* gate). The pool is the single policy-enforcement point; the per-invocation gate
|
|
46
46
|
* applies the policy only when NOT explicit.
|
|
@@ -49,7 +49,7 @@ export interface TaskingEligibilityInput {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export interface TaskingEligibilityResult {
|
|
52
|
-
/** Taskable now = gate passes AND every `taskedAfter`
|
|
52
|
+
/** Taskable now = gate passes AND every `taskedAfter` spec is already tasked. */
|
|
53
53
|
taskable: boolean;
|
|
54
54
|
/** Whether the autonomy gate alone passes (agent-taskable on its own axes). */
|
|
55
55
|
gatePass: boolean;
|
|
@@ -61,7 +61,7 @@ export interface TaskingEligibilityResult {
|
|
|
61
61
|
* `true` AND `humanOnly` is not `true` AND the repo's `autoTask` POLICY is
|
|
62
62
|
* satisfied — where the policy is satisfied either by the repo's `autoTask`
|
|
63
63
|
* toggle being on (the AUTO-PICK pool path) OR by the target being named
|
|
64
|
-
* EXPLICITLY (`explicit: true` — `do
|
|
64
|
+
* EXPLICITLY (`explicit: true` — `do spec:<slug>`, where naming IS the
|
|
65
65
|
* authorization, mirroring `do <task>` vs `autoBuild`). Both readiness axes
|
|
66
66
|
* block orthogonally and are never agent-taskable regardless of policy; a human
|
|
67
67
|
* is never bound by either. The exact mirror of `resolveGate` (the build gate),
|
|
@@ -82,9 +82,9 @@ export function resolveTaskGate(
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Resolve a
|
|
86
|
-
* `done/`): satisfied iff every listed
|
|
87
|
-
* untasked blocker ⇒ not yet taskable (so this
|
|
85
|
+
* Resolve a spec's `taskedAfter` against the slugs of prds already TASKED (NOT
|
|
86
|
+
* `done/`): satisfied iff every listed spec is present in `taskedSlugs`. An
|
|
87
|
+
* untasked blocker ⇒ not yet taskable (so this spec's emitted tasks can
|
|
88
88
|
* reference the real slugs of those prds' tasks).
|
|
89
89
|
*/
|
|
90
90
|
export function resolveTaskedAfter(
|