dorfl 0.1.2 → 0.2.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/advance-drivers.d.ts +1 -1
- package/dist/advance-drivers.d.ts.map +1 -1
- package/dist/advance-drivers.js +15 -3
- package/dist/advance-drivers.js.map +1 -1
- package/dist/advance-lifecycle-template.d.ts.map +1 -1
- package/dist/advance-lifecycle-template.js +76 -4
- package/dist/advance-lifecycle-template.js.map +1 -1
- package/dist/advance-treeless-publish.d.ts +23 -0
- package/dist/advance-treeless-publish.d.ts.map +1 -1
- package/dist/advance-treeless-publish.js +41 -0
- package/dist/advance-treeless-publish.js.map +1 -1
- package/dist/advance.d.ts +59 -7
- package/dist/advance.d.ts.map +1 -1
- package/dist/advance.js +389 -82
- package/dist/advance.js.map +1 -1
- package/dist/advancing-lock.d.ts +30 -2
- package/dist/advancing-lock.d.ts.map +1 -1
- package/dist/advancing-lock.js +50 -0
- package/dist/advancing-lock.js.map +1 -1
- package/dist/agent-launch.d.ts +12 -0
- package/dist/agent-launch.d.ts.map +1 -1
- package/dist/agent-launch.js +22 -12
- package/dist/agent-launch.js.map +1 -1
- package/dist/agent-stop.d.ts +40 -2
- package/dist/agent-stop.d.ts.map +1 -1
- package/dist/agent-stop.js +30 -2
- package/dist/agent-stop.js.map +1 -1
- package/dist/apply-decide.d.ts +17 -3
- package/dist/apply-decide.d.ts.map +1 -1
- package/dist/apply-decide.js +36 -7
- package/dist/apply-decide.js.map +1 -1
- package/dist/apply-merge-action.d.ts +17 -5
- package/dist/apply-merge-action.d.ts.map +1 -1
- package/dist/apply-merge-action.js +43 -8
- package/dist/apply-merge-action.js.map +1 -1
- package/dist/apply-persist.d.ts +57 -26
- package/dist/apply-persist.d.ts.map +1 -1
- package/dist/apply-persist.js +166 -37
- package/dist/apply-persist.js.map +1 -1
- package/dist/apply-stuck-action.d.ts +151 -0
- package/dist/apply-stuck-action.d.ts.map +1 -0
- package/dist/apply-stuck-action.js +125 -0
- package/dist/apply-stuck-action.js.map +1 -0
- package/dist/brand.d.ts +12 -1
- package/dist/brand.d.ts.map +1 -1
- package/dist/brand.js +2 -1
- package/dist/brand.js.map +1 -1
- package/dist/cli-spinner.d.ts +1 -1
- package/dist/cli-spinner.js +1 -1
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +320 -63
- package/dist/cli.js.map +1 -1
- package/dist/close-job-template.js +1 -1
- package/dist/complete.d.ts +6 -3
- package/dist/complete.d.ts.map +1 -1
- package/dist/complete.js +91 -37
- package/dist/complete.js.map +1 -1
- package/dist/config.d.ts +55 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +56 -4
- package/dist/config.js.map +1 -1
- package/dist/continue-branch.d.ts.map +1 -1
- package/dist/continue-branch.js +22 -0
- package/dist/continue-branch.js.map +1 -1
- package/dist/decision-engine.d.ts +38 -10
- package/dist/decision-engine.d.ts.map +1 -1
- package/dist/decision-engine.js +10 -6
- package/dist/decision-engine.js.map +1 -1
- package/dist/do-autopick.d.ts.map +1 -1
- package/dist/do-autopick.js +11 -1
- package/dist/do-autopick.js.map +1 -1
- package/dist/do-config.d.ts +1 -1
- package/dist/do.d.ts +49 -56
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +419 -30
- package/dist/do.js.map +1 -1
- package/dist/env-config.d.ts.map +1 -1
- package/dist/env-config.js +12 -4
- package/dist/env-config.js.map +1 -1
- package/dist/failure-cause.d.ts +3 -2
- package/dist/failure-cause.d.ts.map +1 -1
- package/dist/failure-cause.js +28 -1
- package/dist/failure-cause.js.map +1 -1
- package/dist/format.d.ts +6 -6
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +10 -27
- package/dist/format.js.map +1 -1
- package/dist/frontmatter.d.ts +16 -4
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +27 -1
- package/dist/frontmatter.js.map +1 -1
- package/dist/gc.d.ts +65 -6
- package/dist/gc.d.ts.map +1 -1
- package/dist/gc.js +126 -9
- package/dist/gc.js.map +1 -1
- package/dist/github.d.ts +14 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +73 -0
- package/dist/github.js.map +1 -1
- package/dist/harness.d.ts +25 -0
- package/dist/harness.d.ts.map +1 -1
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/install-ci-branch-protection.d.ts +132 -38
- package/dist/install-ci-branch-protection.d.ts.map +1 -1
- package/dist/install-ci-branch-protection.js +190 -48
- package/dist/install-ci-branch-protection.js.map +1 -1
- package/dist/install-ci-core.d.ts +21 -1
- package/dist/install-ci-core.d.ts.map +1 -1
- package/dist/install-ci-core.js +10 -3
- package/dist/install-ci-core.js.map +1 -1
- package/dist/install-ci-github.d.ts +32 -0
- package/dist/install-ci-github.d.ts.map +1 -1
- package/dist/install-ci-github.js +73 -0
- package/dist/install-ci-github.js.map +1 -1
- package/dist/install-skills.d.ts +123 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +100 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/intake-trigger-template.js +1 -1
- package/dist/intake.d.ts +17 -4
- package/dist/intake.d.ts.map +1 -1
- package/dist/intake.js +23 -7
- package/dist/intake.js.map +1 -1
- package/dist/integration-core.d.ts +10 -7
- package/dist/integration-core.d.ts.map +1 -1
- package/dist/integration-core.js +174 -60
- package/dist/integration-core.js.map +1 -1
- package/dist/integrator.d.ts +1 -1
- package/dist/integrator.d.ts.map +1 -1
- package/dist/integrator.js +19 -3
- package/dist/integrator.js.map +1 -1
- package/dist/isolation.d.ts +2 -2
- package/dist/isolation.d.ts.map +1 -1
- package/dist/isolation.js +9 -0
- package/dist/isolation.js.map +1 -1
- package/dist/item-lock.d.ts +196 -129
- package/dist/item-lock.d.ts.map +1 -1
- package/dist/item-lock.js +329 -254
- package/dist/item-lock.js.map +1 -1
- package/dist/ledger-write.d.ts +31 -26
- package/dist/ledger-write.d.ts.map +1 -1
- package/dist/ledger-write.js +100 -122
- package/dist/ledger-write.js.map +1 -1
- package/dist/lifecycle-gather.d.ts +17 -0
- package/dist/lifecycle-gather.d.ts.map +1 -1
- package/dist/lifecycle-gather.js +7 -1
- package/dist/lifecycle-gather.js.map +1 -1
- package/dist/lifecycle-pools.d.ts +40 -3
- package/dist/lifecycle-pools.d.ts.map +1 -1
- package/dist/lifecycle-pools.js +26 -6
- package/dist/lifecycle-pools.js.map +1 -1
- package/dist/merge-question-surfacer.d.ts +15 -1
- package/dist/merge-question-surfacer.d.ts.map +1 -1
- package/dist/merge-question-surfacer.js +18 -3
- package/dist/merge-question-surfacer.js.map +1 -1
- package/dist/migrate-stuck-locks.d.ts +129 -0
- package/dist/migrate-stuck-locks.d.ts.map +1 -0
- package/dist/migrate-stuck-locks.js +355 -0
- package/dist/migrate-stuck-locks.js.map +1 -0
- package/dist/needs-attention.d.ts +293 -16
- package/dist/needs-attention.d.ts.map +1 -1
- package/dist/needs-attention.js +532 -57
- package/dist/needs-attention.js.map +1 -1
- package/dist/orphan-sidecar.d.ts +8 -4
- package/dist/orphan-sidecar.d.ts.map +1 -1
- package/dist/orphan-sidecar.js +35 -2
- package/dist/orphan-sidecar.js.map +1 -1
- package/dist/pi-harness.d.ts +16 -0
- package/dist/pi-harness.d.ts.map +1 -1
- package/dist/pi-harness.js +82 -2
- package/dist/pi-harness.js.map +1 -1
- package/dist/placement.d.ts +3 -3
- package/dist/placement.js +1 -1
- package/dist/prd-to-spec.d.ts.map +1 -1
- package/dist/prd-to-spec.js +9 -5
- package/dist/prd-to-spec.js.map +1 -1
- package/dist/protocol/CLAIM-PROTOCOL.md +17 -10
- package/dist/protocol/REVIEW-PROTOCOL.md +4 -1
- package/dist/protocol/SURFACE-PROTOCOL.md +16 -2
- package/dist/protocol/TASKING-PROTOCOL.md +3 -1
- package/dist/protocol/WORK-CONTRACT.md +22 -18
- package/dist/protocol/task-template.md +1 -1
- package/dist/reap-branches.d.ts +12 -9
- package/dist/reap-branches.d.ts.map +1 -1
- package/dist/reap-branches.js +25 -7
- package/dist/reap-branches.js.map +1 -1
- package/dist/recover-isolated.d.ts +12 -0
- package/dist/recover-isolated.d.ts.map +1 -1
- package/dist/recover-isolated.js +5 -0
- package/dist/recover-isolated.js.map +1 -1
- package/dist/repo-config.d.ts +23 -2
- package/dist/repo-config.d.ts.map +1 -1
- package/dist/repo-config.js +53 -7
- package/dist/repo-config.js.map +1 -1
- package/dist/repo-mirror.d.ts.map +1 -1
- package/dist/repo-mirror.js +18 -2
- package/dist/repo-mirror.js.map +1 -1
- package/dist/review-verdict.js +1 -1
- package/dist/review-verdict.js.map +1 -1
- package/dist/run.d.ts +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +54 -19
- package/dist/run.js.map +1 -1
- package/dist/scan.d.ts +17 -8
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +22 -8
- package/dist/scan.js.map +1 -1
- package/dist/select-priority.d.ts +2 -2
- package/dist/select-priority.js +1 -1
- package/dist/select-priority.js.map +1 -1
- package/dist/sidecar-apply.js +1 -1
- package/dist/sidecar-apply.js.map +1 -1
- package/dist/sidecar.d.ts +45 -10
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +82 -2
- package/dist/sidecar.js.map +1 -1
- package/dist/skills/answer-questions/SKILL.md +89 -0
- package/dist/skills/capture-signal/SKILL.md +52 -0
- package/dist/skills/convert-from-prd-to-spec/SKILL.md +90 -0
- package/dist/skills/drive-tasks/SKILL.md +218 -0
- package/dist/skills/from-idea/SKILL.md +83 -0
- package/dist/skills/merge-prs/SKILL.md +70 -0
- package/dist/skills/orchestrate/SKILL.md +101 -0
- package/dist/skills/promote/SKILL.md +35 -0
- package/dist/skills/review/SKILL.md +16 -0
- package/dist/skills/setup/SKILL.md +258 -0
- package/dist/skills/setup/protocol/ADR-FORMAT.md +47 -0
- package/dist/skills/setup/protocol/CLAIM-PROTOCOL.md +224 -0
- package/dist/skills/setup/protocol/REVIEW-PROTOCOL.md +122 -0
- package/dist/skills/setup/protocol/SURFACE-PROTOCOL.md +135 -0
- package/dist/skills/setup/protocol/TASKING-PROTOCOL.md +124 -0
- package/dist/skills/setup/protocol/WORK-CONTRACT.md +280 -0
- package/dist/skills/setup/protocol/spec-template.md +71 -0
- package/dist/skills/setup/protocol/task-template.md +65 -0
- package/dist/skills/surface-questions/SKILL.md +16 -0
- package/dist/skills/to-spec/SKILL.md +34 -0
- package/dist/skills/to-task/SKILL.md +19 -0
- package/dist/skills/triage-observations/SKILL.md +78 -0
- package/dist/skills/work/SKILL.md +51 -0
- package/dist/slug-namespace.d.ts +5 -5
- package/dist/slug-namespace.js +5 -5
- package/dist/slug-namespace.js.map +1 -1
- package/dist/spec-complete.d.ts.map +1 -1
- package/dist/spec-complete.js +2 -3
- package/dist/spec-complete.js.map +1 -1
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +51 -57
- package/dist/start.js.map +1 -1
- package/dist/surface-gate.d.ts.map +1 -1
- package/dist/surface-gate.js +10 -3
- package/dist/surface-gate.js.map +1 -1
- package/dist/surface-persist.js +1 -1
- package/dist/surface-persist.js.map +1 -1
- package/dist/tasker-review-loop.d.ts +4 -3
- package/dist/tasker-review-loop.d.ts.map +1 -1
- package/dist/tasker-review-loop.js.map +1 -1
- package/dist/tasking-lock.d.ts +2 -2
- package/dist/tasking-lock.d.ts.map +1 -1
- package/dist/tasking-lock.js +53 -32
- package/dist/tasking-lock.js.map +1 -1
- package/dist/tasking.d.ts +40 -6
- package/dist/tasking.d.ts.map +1 -1
- package/dist/tasking.js +224 -12
- package/dist/tasking.js.map +1 -1
- package/dist/triage-persist.d.ts +10 -6
- package/dist/triage-persist.d.ts.map +1 -1
- package/dist/triage-persist.js +34 -4
- package/dist/triage-persist.js.map +1 -1
- package/dist/vendor/incur/agents.d.ts +58 -0
- package/dist/vendor/incur/agents.d.ts.map +1 -0
- package/dist/vendor/incur/agents.js +343 -0
- package/dist/vendor/incur/agents.js.map +1 -0
- package/dist/verify-workflow-template.js +1 -1
- package/dist/watch-session.d.ts +11 -3
- package/dist/watch-session.d.ts.map +1 -1
- package/dist/watch-session.js +94 -7
- package/dist/watch-session.js.map +1 -1
- package/dist/work-layout.d.ts +7 -3
- package/dist/work-layout.d.ts.map +1 -1
- package/dist/work-layout.js +6 -3
- package/dist/work-layout.js.map +1 -1
- package/dist/workspace.d.ts +1 -1
- package/package.json +2 -2
- package/src/advance-drivers.ts +16 -3
- package/src/advance-lifecycle-template.ts +89 -4
- package/src/advance-treeless-publish.ts +45 -0
- package/src/advance.ts +467 -87
- package/src/advancing-lock.ts +96 -1
- package/src/agent-launch.ts +37 -12
- package/src/agent-stop.ts +60 -2
- package/src/apply-decide.ts +36 -7
- package/src/apply-merge-action.ts +45 -7
- package/src/apply-persist.ts +228 -54
- package/src/apply-stuck-action.ts +260 -0
- package/src/brand.ts +14 -2
- package/src/cli-spinner.ts +1 -1
- package/src/cli.ts +401 -70
- package/src/close-job-template.ts +1 -1
- package/src/complete.ts +110 -52
- package/src/config.ts +107 -13
- package/src/continue-branch.ts +22 -0
- package/src/decision-engine.ts +55 -17
- package/src/do-autopick.ts +12 -1
- package/src/do-config.ts +1 -1
- package/src/do.ts +511 -38
- package/src/env-config.ts +12 -4
- package/src/failure-cause.ts +30 -1
- package/src/format.ts +10 -30
- package/src/frontmatter.ts +35 -5
- package/src/gc.ts +172 -9
- package/src/github.ts +78 -0
- package/src/harness.ts +25 -0
- package/src/index.ts +10 -0
- package/src/install-ci-branch-protection.ts +282 -57
- package/src/install-ci-core.ts +30 -3
- package/src/install-ci-github.ts +86 -0
- package/src/install-skills.ts +166 -0
- package/src/intake-trigger-template.ts +1 -1
- package/src/intake.ts +46 -11
- package/src/integration-core.ts +199 -65
- package/src/integrator.ts +22 -9
- package/src/isolation.ts +11 -2
- package/src/item-lock.ts +485 -341
- package/src/ledger-write.ts +135 -150
- package/src/lifecycle-gather.ts +29 -6
- package/src/lifecycle-pools.ts +67 -9
- package/src/merge-question-surfacer.ts +28 -4
- package/src/migrate-stuck-locks.ts +451 -0
- package/src/needs-attention.ts +857 -84
- package/src/orphan-sidecar.ts +47 -6
- package/src/pi-harness.ts +82 -2
- package/src/placement.ts +3 -3
- package/src/prd-to-spec.ts +13 -5
- package/src/reap-branches.ts +38 -14
- package/src/recover-isolated.ts +17 -0
- package/src/repo-config.ts +55 -6
- package/src/repo-mirror.ts +23 -1
- package/src/review-verdict.ts +1 -1
- package/src/run.ts +64 -18
- package/src/scan.ts +22 -8
- package/src/select-priority.ts +3 -3
- package/src/sidecar-apply.ts +1 -1
- package/src/sidecar.ts +138 -11
- package/src/slug-namespace.ts +7 -7
- package/src/spec-complete.ts +2 -3
- package/src/start.ts +53 -59
- package/src/surface-gate.ts +10 -3
- package/src/surface-persist.ts +1 -1
- package/src/tasker-review-loop.ts +4 -3
- package/src/tasking-lock.ts +52 -36
- package/src/tasking.ts +261 -17
- package/src/triage-persist.ts +56 -12
- package/src/vendor/incur/LICENSE +21 -0
- package/src/vendor/incur/README.md +19 -0
- package/src/vendor/incur/agents.ts +392 -0
- package/src/verify-workflow-template.ts +1 -1
- package/src/watch-session.ts +102 -7
- package/src/work-layout.ts +6 -3
- package/src/workspace.ts +1 -1
package/src/ledger-write.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {IntegrationMode} from './config.js';
|
|
|
9
9
|
import {
|
|
10
10
|
routeToNeedsAttention,
|
|
11
11
|
returnToBacklog,
|
|
12
|
+
surfaceStuckToNeedsAttention,
|
|
12
13
|
type RouteToNeedsAttentionOptions,
|
|
13
14
|
type RouteToNeedsAttentionResult,
|
|
14
15
|
type ReturnToBacklogOptions,
|
|
@@ -17,11 +18,7 @@ import {
|
|
|
17
18
|
type SurfaceToNeedsAttentionResult,
|
|
18
19
|
type BranchPushOutcome,
|
|
19
20
|
} from './needs-attention.js';
|
|
20
|
-
import {
|
|
21
|
-
markStuckItemLock,
|
|
22
|
-
resumeItemLock,
|
|
23
|
-
type TransitionOutcome,
|
|
24
|
-
} from './item-lock.js';
|
|
21
|
+
import type {NewQuestion} from './sidecar.js';
|
|
25
22
|
|
|
26
23
|
/**
|
|
27
24
|
* The **write half** of the ledger-transition seam (ADR
|
|
@@ -91,7 +88,7 @@ export type LedgerTransitionKind =
|
|
|
91
88
|
/**
|
|
92
89
|
* The **promote** transition (spec `staging-pool-position-gate-and-trust-model`,
|
|
93
90
|
* task `pre-backlog-staging-folder-and-promote-step-a`): move a STAGED task
|
|
94
|
-
* `work/
|
|
91
|
+
* `work/tasks/backlog/<slug>.md → work/tasks/ready/<slug>.md` to enter the
|
|
95
92
|
* agent-eligible pool. A durable `main` move, the same category as `requeue`
|
|
96
93
|
* (tree-less CAS via {@link applyTransition}). RUNNER/human-owned — no
|
|
97
94
|
* agent-facing path performs it (governing ADR
|
|
@@ -158,14 +155,15 @@ export interface ApplyCompleteTransitionInput {
|
|
|
158
155
|
export type ApplyCompleteTransitionResult = IntegrateResult;
|
|
159
156
|
|
|
160
157
|
/**
|
|
161
|
-
* A *prepared* NEEDS-ATTENTION transition the caller asks the seam to apply:
|
|
162
|
-
* stuck claimed item
|
|
163
|
-
*
|
|
164
|
-
* any surfaced questions, and an OPTIONAL arbiter to also push the branch
|
|
165
|
-
* NOT *where* the
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* mirrors {@link RouteToNeedsAttentionOptions} so the
|
|
158
|
+
* A *prepared* NEEDS-ATTENTION transition the caller asks the seam to apply:
|
|
159
|
+
* mark a stuck claimed item on its per-item lock with the reason. Like the
|
|
160
|
+
* other inputs it is storage-agnostic — it names the slug, the reason prose,
|
|
161
|
+
* any surfaced questions, and an OPTIONAL arbiter to also push the work branch
|
|
162
|
+
* to, NOT *where* the surface commits/publishes (the sole strategy decides
|
|
163
|
+
* that: post lock-cutover, a lock amend to `state: stuck` with the reason on
|
|
164
|
+
* the lock entry — no `work/needs-attention/` folder write — plus the optional
|
|
165
|
+
* branch push). This mirrors {@link RouteToNeedsAttentionOptions} so the
|
|
166
|
+
* mechanism stays unchanged.
|
|
169
167
|
*/
|
|
170
168
|
export type ApplyNeedsAttentionTransitionInput = RouteToNeedsAttentionOptions;
|
|
171
169
|
|
|
@@ -181,9 +179,10 @@ export type ApplyNeedsAttentionTransitionResult = RouteToNeedsAttentionResult;
|
|
|
181
179
|
|
|
182
180
|
/**
|
|
183
181
|
* A *prepared* RETURN-TO-BACKLOG transition: re-queue a STUCK item so it can be
|
|
184
|
-
* re-claimed — recovered
|
|
185
|
-
*
|
|
186
|
-
*
|
|
182
|
+
* re-claimed — recovered via its per-item lock on the arbiter (post lock-cutover
|
|
183
|
+
* the body never moved into a status folder; it rests in `backlog/`, so requeue
|
|
184
|
+
* releases/clears the lock rather than moving a `.md`). Covers both a resolved
|
|
185
|
+
* stuck hold and a claim that never surfaced.
|
|
187
186
|
* Storage-agnostic, mirroring {@link ReturnToBacklogOptions}.
|
|
188
187
|
*/
|
|
189
188
|
export type ApplyReturnToBacklogTransitionInput = ReturnToBacklogOptions;
|
|
@@ -198,11 +197,12 @@ export type ApplyReturnToBacklogTransitionResult =
|
|
|
198
197
|
|
|
199
198
|
/**
|
|
200
199
|
* A *prepared* TREE-LESS NEEDS-ATTENTION (surface) transition: surface a stuck
|
|
201
|
-
* AFTER-COMMIT, LEDGER-ONLY item (
|
|
202
|
-
*
|
|
200
|
+
* AFTER-COMMIT, LEDGER-ONLY item (post lock-cutover — mark its per-item lock
|
|
201
|
+
* `state: stuck` with the reason, no `in-progress/ → needs-attention/` folder
|
|
202
|
+
* move) WITHOUT a checkout — the SURFACE-direction sibling of the
|
|
203
203
|
* tree-less requeue, sharing its exact mechanism. The work is ALREADY committed
|
|
204
204
|
* on the kept `work/<slug>` branch (intact on the arbiter, recoverable), so the
|
|
205
|
-
* surface is purely the
|
|
205
|
+
* surface is purely the lock amend + reason — no `pushBranch`, no
|
|
206
206
|
* worktree. Storage-agnostic, mirroring {@link SurfaceToNeedsAttentionOptions}.
|
|
207
207
|
* NOT for the wip-save / gate-failed / agent-failed surfaces (which may carry
|
|
208
208
|
* uncommitted work — those keep {@link applyNeedsAttentionTransition}, the
|
|
@@ -322,21 +322,22 @@ export interface LedgerWriteStrategy {
|
|
|
322
322
|
input: ApplyCompleteTransitionInput,
|
|
323
323
|
): Promise<ApplyCompleteTransitionResult>;
|
|
324
324
|
/**
|
|
325
|
-
* Apply a NEEDS-ATTENTION transition:
|
|
326
|
-
*
|
|
327
|
-
* strategy delegates to the
|
|
328
|
-
* strategy could surface the stuck item elsewhere
|
|
329
|
-
* `
|
|
325
|
+
* Apply a NEEDS-ATTENTION transition: mark a stuck claimed item on its
|
|
326
|
+
* per-item lock with its reason (post lock-cutover — no folder write). The
|
|
327
|
+
* sole strategy delegates to the underlying mechanism unchanged; a future
|
|
328
|
+
* strategy could surface the stuck item elsewhere without
|
|
329
|
+
* `complete.ts`/`run.ts` changing.
|
|
330
330
|
*/
|
|
331
331
|
applyNeedsAttentionTransition(
|
|
332
332
|
input: ApplyNeedsAttentionTransitionInput,
|
|
333
333
|
): Promise<ApplyNeedsAttentionTransitionResult>;
|
|
334
334
|
/**
|
|
335
335
|
* Apply a TREE-LESS NEEDS-ATTENTION (surface) transition: surface a stuck
|
|
336
|
-
* AFTER-COMMIT, LEDGER-ONLY item (
|
|
336
|
+
* AFTER-COMMIT, LEDGER-ONLY item (post lock-cutover — mark its per-item lock
|
|
337
|
+
* `state: stuck`, no `in-progress/ → needs-attention/` folder move) WITHOUT a
|
|
337
338
|
* checkout, reusing the SAME tree-less mechanism `requeue` uses for the reverse
|
|
338
|
-
* direction. The sole strategy delegates to the tree-less surface (
|
|
339
|
-
*
|
|
339
|
+
* direction. The sole strategy delegates to the tree-less surface (a pure lock
|
|
340
|
+
* amend CAS-published to the arbiter's lock ref). NOT
|
|
340
341
|
* for the uncommitted-wip surfaces, which keep {@link
|
|
341
342
|
* applyNeedsAttentionTransition} (the cwd-bound path that can commit wip first).
|
|
342
343
|
*/
|
|
@@ -344,10 +345,11 @@ export interface LedgerWriteStrategy {
|
|
|
344
345
|
input: ApplyTreelessNeedsAttentionTransitionInput,
|
|
345
346
|
): ApplyTreelessNeedsAttentionTransitionResult;
|
|
346
347
|
/**
|
|
347
|
-
* Apply a RETURN-TO-BACKLOG transition: re-queue a STUCK item (
|
|
348
|
-
*
|
|
348
|
+
* Apply a RETURN-TO-BACKLOG transition: re-queue a STUCK item (recovered via
|
|
349
|
+
* its per-item lock on the arbiter — post lock-cutover the body rests in
|
|
350
|
+
* `backlog/`, not a status folder) for
|
|
349
351
|
* re-claiming, routed through the SAME seam. Like `claim`, it is TREE-LESS —
|
|
350
|
-
* the
|
|
352
|
+
* the amend is a compare-and-swap push to the arbiter ref (it never writes the
|
|
351
353
|
* cwd tree).
|
|
352
354
|
*/
|
|
353
355
|
applyReturnToBacklogTransition(
|
|
@@ -630,12 +632,12 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
|
|
|
630
632
|
* bounce its `work/prd-<slug>`, a temp-branch caller pushes NOTHING.)
|
|
631
633
|
*
|
|
632
634
|
* Both halves are ONE operation done in ONE place: it delegates to {@link
|
|
633
|
-
* routeToNeedsAttention}, which
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
635
|
+
* routeToNeedsAttention}, which saves the aborted work as a **wip** commit
|
|
636
|
+
* on the work branch (post lock-cutover no `work/needs-attention/` folder
|
|
637
|
+
* write ever fires here) and — when an `arbiter` is given — pushes the work
|
|
638
|
+
* branch (best-effort, branch-parameterised, emptiness-guarded; SURFACE-
|
|
639
|
+
* ONLY when `pushBranch: false`). The OBSERVABLE lock amend rides on
|
|
640
|
+
* {@link bounceToStuckLock} directly below. The seam does NOT strip the arbiter: the same
|
|
639
641
|
* arbiter both publishes the surface (here) AND drives the helper's branch push,
|
|
640
642
|
* so "record stuck" and "save the work" can never drift apart. The human-vs-
|
|
641
643
|
* autonomous gate rides on whether an `arbiter` is given at all (human
|
|
@@ -657,9 +659,10 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
|
|
|
657
659
|
// outage-retried), so the partial work travels cross-machine and a `requeue`
|
|
658
660
|
// continues from the tip. The work-branch push is NOT a `main` write.
|
|
659
661
|
const saved = await routeToNeedsAttention(input);
|
|
660
|
-
const
|
|
662
|
+
const surfaced = await bounceThroughSurface({
|
|
661
663
|
cwd: input.cwd,
|
|
662
664
|
slug: input.slug,
|
|
665
|
+
item: `task:${input.slug}`,
|
|
663
666
|
reason: input.reason,
|
|
664
667
|
questions: input.questions,
|
|
665
668
|
arbiter: input.arbiter,
|
|
@@ -667,11 +670,12 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
|
|
|
667
670
|
note: input.note,
|
|
668
671
|
});
|
|
669
672
|
return {
|
|
670
|
-
// `moved` reflects the OBSERVABLE half (the
|
|
671
|
-
|
|
672
|
-
|
|
673
|
+
// `moved` reflects the OBSERVABLE half (the surface record): the sidecar +
|
|
674
|
+
// `needsAnswers:true` on `<arbiter>/main` (or the human-local no-op).
|
|
675
|
+
moved: surfaced.moved,
|
|
676
|
+
reasonNotMoved: surfaced.reasonNotMoved,
|
|
673
677
|
// The branch push outcome is the honest RECOVERABLE report (`do`/`run` read
|
|
674
|
-
// it).
|
|
678
|
+
// it).
|
|
675
679
|
branchPush: saved.branchPush,
|
|
676
680
|
pushError: saved.pushError,
|
|
677
681
|
};
|
|
@@ -680,7 +684,7 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
|
|
|
680
684
|
/**
|
|
681
685
|
* The return-to-backlog transition under the SAME strategy: re-queue the
|
|
682
686
|
* stuck item by delegating to {@link returnToBacklog}, which moves the slug's
|
|
683
|
-
* current `work/<needs-attention|in-progress>/<slug>.md → work/
|
|
687
|
+
* current `work/<needs-attention|in-progress>/<slug>.md → work/tasks/ready/<slug>.md`
|
|
684
688
|
* TREE-LESSLY — it
|
|
685
689
|
* builds the move off `<arbiter>/main` with plumbing and CAS-publishes it back
|
|
686
690
|
* THROUGH this same write seam (`applyTransition`, the very push+lease+verify
|
|
@@ -693,165 +697,146 @@ export const currentLedgerWrite: LedgerWriteStrategy = {
|
|
|
693
697
|
},
|
|
694
698
|
|
|
695
699
|
/**
|
|
696
|
-
* The tree-less surface transition under the SAME strategy: surface the
|
|
697
|
-
* AFTER-COMMIT, LEDGER-ONLY item by delegating to the tree-less
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
* staging/committing in the cwd working tree. The reverse of
|
|
700
|
+
* The tree-less surface transition under the SAME strategy: surface the
|
|
701
|
+
* stuck AFTER-COMMIT, LEDGER-ONLY item by delegating to the tree-less
|
|
702
|
+
* surface — post lock-cutover a pure LOCK AMEND (`state: stuck` with the
|
|
703
|
+
* reason on the lock entry), CAS-published to the arbiter's lock ref via
|
|
704
|
+
* the same push+lease+verify seam `claim`/`requeue` use, never staging or
|
|
705
|
+
* committing in the cwd working tree. The reverse of
|
|
703
706
|
* {@link applyReturnToBacklogTransition}, the same one mechanism.
|
|
704
707
|
*/
|
|
705
708
|
async applyTreelessNeedsAttentionTransition(
|
|
706
709
|
input: ApplyTreelessNeedsAttentionTransitionInput,
|
|
707
710
|
): ApplyTreelessNeedsAttentionTransitionResult {
|
|
708
|
-
//
|
|
709
|
-
// `
|
|
710
|
-
//
|
|
711
|
-
//
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
//
|
|
715
|
-
// already
|
|
716
|
-
const
|
|
711
|
+
// PR-2b surface cutover (spec
|
|
712
|
+
// `surface-stuck-as-questions-and-retire-stuck-lock-state`, decision #1): the
|
|
713
|
+
// after-commit / ledger-only surface (continue-push-failure / continue-rebase-
|
|
714
|
+
// conflict) surfaces the item on `<arbiter>/main` (a `stuck`-kind sidecar +
|
|
715
|
+
// `needsAnswers:true` on the item body in ONE commit) THEN releases the per-
|
|
716
|
+
// item lock. Surface-FIRST, release-SECOND, with `main`-authoritative crash
|
|
717
|
+
// recovery inherited from {@link runTreelessLedgerMove}. The recoverable work
|
|
718
|
+
// is already committed on the kept `work/<slug>` branch (intact on the arbiter).
|
|
719
|
+
const surfaced = await bounceThroughSurface({
|
|
717
720
|
cwd: input.cwd,
|
|
718
721
|
slug: input.slug,
|
|
722
|
+
item: `task:${input.slug}`,
|
|
719
723
|
reason: input.reason,
|
|
720
724
|
questions: input.questions,
|
|
721
725
|
arbiter: input.arbiter,
|
|
722
726
|
env: input.env,
|
|
723
727
|
note: input.note,
|
|
724
728
|
});
|
|
725
|
-
return {moved:
|
|
729
|
+
return {moved: surfaced.moved, reasonNotMoved: surfaced.reasonNotMoved};
|
|
726
730
|
},
|
|
727
731
|
|
|
728
732
|
/**
|
|
729
733
|
* The resolve-needs-attention transition under the SAME strategy — satisfying
|
|
730
|
-
* the INTENT "clear the stuck surface + restore
|
|
731
|
-
* the resume lock amend (
|
|
732
|
-
* in-progress
|
|
733
|
-
*
|
|
734
|
-
* there (the item is
|
|
735
|
-
* never-`--force` publish.
|
|
736
|
-
* strategy; the seam's contract is only the intent "clear the surface."
|
|
734
|
+
* the INTENT "clear the stuck surface + restore active." It delegates to
|
|
735
|
+
* the resume lock amend (post lock-cutover — `stuck → active` on the per-item
|
|
736
|
+
* lock, no reverse `needs-attention/ → in-progress/` folder move) and, when an
|
|
737
|
+
* `arbiter` is given, CAS-publishes that lock amend to the arbiter's lock ref —
|
|
738
|
+
* CLEARING the stuck surface there (the item is active again). Same
|
|
739
|
+
* all-or-nothing, never-`--force` publish. The lock-ref amend is a detail of
|
|
740
|
+
* THIS strategy; the seam's contract is only the intent "clear the surface."
|
|
737
741
|
*/
|
|
738
742
|
async applyResolveNeedsAttentionTransition(
|
|
739
|
-
|
|
743
|
+
_input: ApplyResolveNeedsAttentionTransitionInput,
|
|
740
744
|
): Promise<ApplyResolveNeedsAttentionTransitionResult> {
|
|
741
|
-
//
|
|
742
|
-
// `
|
|
743
|
-
//
|
|
744
|
-
//
|
|
745
|
-
//
|
|
746
|
-
//
|
|
747
|
-
//
|
|
748
|
-
|
|
749
|
-
return {moved: true};
|
|
750
|
-
}
|
|
751
|
-
const r = await resumeItemLock({
|
|
752
|
-
item: `task:${input.slug}`,
|
|
753
|
-
cwd: input.cwd,
|
|
754
|
-
arbiter: input.arbiter,
|
|
755
|
-
env: input.env,
|
|
756
|
-
});
|
|
757
|
-
if (r.outcome === 'transitioned') {
|
|
758
|
-
return {moved: true};
|
|
759
|
-
}
|
|
760
|
-
// `wrong-state` (already active — not actually stuck) is tolerated as a no-op
|
|
761
|
-
// success: the item is already in-flight, the caller onboards onto it anyway.
|
|
762
|
-
if (r.outcome === 'wrong-state') {
|
|
763
|
-
return {moved: true};
|
|
764
|
-
}
|
|
765
|
-
return {
|
|
766
|
-
moved: false,
|
|
767
|
-
reasonNotMoved: `could not resume '${input.slug}' (${r.outcome}: ${r.message}).`,
|
|
768
|
-
};
|
|
745
|
+
// Post-`retire-stuck-lock-state`: the `stuck` lock state is retired, so
|
|
746
|
+
// there is no `stuck → active` lock amend to perform. A parked item is
|
|
747
|
+
// now a `needsAnswers:true` pool item on `main` with a sidecar, drained
|
|
748
|
+
// by the apply rung (answer the sidecar), not by a resolve verb. The seam
|
|
749
|
+
// is kept for source compatibility of its remaining legacy callers
|
|
750
|
+
// (start.ts's legacy `needs-attention/` folder branch), where it is a
|
|
751
|
+
// recorded no-op success.
|
|
752
|
+
return {moved: true};
|
|
769
753
|
},
|
|
770
754
|
};
|
|
771
755
|
|
|
772
756
|
/**
|
|
773
|
-
* The SOLE stuck-state RECORD
|
|
774
|
-
* `
|
|
775
|
-
*
|
|
776
|
-
* `
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
* bounce
|
|
782
|
-
*
|
|
783
|
-
* The bounce holds the TASK's `implement` lock that `claim` acquired (task
|
|
784
|
-
* `claim-acquires-unified-lock-no-body-move`), so the normal stuck path is a plain
|
|
785
|
-
* `active → stuck` amend (`transitioned`). The OUTCOME MAPPING onto `{moved}`:
|
|
786
|
-
* - `transitioned` — the lock is now stuck (the stuck state is recorded) ⇒
|
|
787
|
-
* `moved: true`.
|
|
788
|
-
* - `wrong-state` — the lock is ALREADY `stuck` (an idempotent re-surface of a
|
|
789
|
-
* still-stuck item) ⇒ `moved: true` (the stuck record stands).
|
|
790
|
-
* - `not-held` — there is NO held lock to amend (an item that predates the
|
|
791
|
-
* lock, or a flow where claim did not acquire) ⇒ `moved: false` honestly: with
|
|
792
|
-
* the folder retired there is no other substrate to record the stuck state on,
|
|
793
|
-
* so the caller reports the bounce did NOT land (retry/resolve) rather than
|
|
794
|
-
* fake a success.
|
|
795
|
-
* - `lost`/`error` — a concurrent CAS race / environment fault ⇒ `moved: false`.
|
|
796
|
-
* - no arbiter — a human local-only `complete` (no arbiter handle): the lock
|
|
797
|
-
* ref lives on the arbiter, so there is no lock to amend; treat as a recorded
|
|
798
|
-
* no-op (`moved: true`) — a human is right there (the same human-vs-autonomous
|
|
799
|
-
* posture the old local-only folder move took). NOTE this records nothing
|
|
800
|
-
* durable, by design: the human is in the loop.
|
|
757
|
+
* The SOLE stuck-state RECORD (PR-2b, spec
|
|
758
|
+
* `surface-stuck-as-questions-and-retire-stuck-lock-state`, user stories 1/3/8,
|
|
759
|
+
* decisions #1/#4): surface the bounced item as a `stuck`-kind sidecar +
|
|
760
|
+
* `needsAnswers:true` on the item body in ONE commit on `<arbiter>/main`, THEN
|
|
761
|
+
* release the per-item lock. Surface-FIRST, release-SECOND — the ordering is
|
|
762
|
+
* load-bearing so a crash between them is recoverable from `main` (the classifier
|
|
763
|
+
* fold in `item-lock.ts` re-derives `cleared-stale` from the main-side truth
|
|
764
|
+
* PR-2a landed). This REPLACES the retired `active → stuck` lock amend: no
|
|
765
|
+
* bounce leaves a `stuck` lock; a bounced item rests as a plain `needsAnswers:true`
|
|
766
|
+
* pool item (`eligible:false` by construction).
|
|
801
767
|
*
|
|
802
|
-
*
|
|
803
|
-
*
|
|
768
|
+
* The OUTCOME MAPPING onto `{moved}`:
|
|
769
|
+
* - `surfaced` — the sidecar + `needsAnswers:true` commit landed on
|
|
770
|
+
* `<arbiter>/main` and the lock was released ⇒ `moved: true`.
|
|
771
|
+
* - `bodyAbsent` — the D1 probe found no body for the item on `main` (a
|
|
772
|
+
* bounce for an item whose body never landed — e.g. a claim that lost/raced).
|
|
773
|
+
* The surface is a CLEAN NO-OP; the lock is STILL released so the bounce is
|
|
774
|
+
* never a dead-end held lock ⇒ `moved: true` (nothing to record, nothing left
|
|
775
|
+
* stuck).
|
|
776
|
+
* - `!surfaced` — the surface commit did NOT land (contention exhausted,
|
|
777
|
+
* item missing on main by explicit path, environment fault) ⇒ `moved: false`
|
|
778
|
+
* with `reasonNotMoved` so the caller reports the honest not-landed state.
|
|
779
|
+
* - no arbiter — a human local-only `complete` (no arbiter handle): the
|
|
780
|
+
* surface primitive requires an arbiter, so this is a recorded no-op (`moved:
|
|
781
|
+
* true`) — a human is right there (the same human-vs-autonomous posture the
|
|
782
|
+
* retired lock amend took). NOTE this records nothing durable, by design.
|
|
804
783
|
*/
|
|
805
|
-
async function
|
|
784
|
+
async function bounceThroughSurface(params: {
|
|
806
785
|
cwd: string;
|
|
807
786
|
slug: string;
|
|
787
|
+
item: string;
|
|
808
788
|
reason: string;
|
|
809
789
|
questions?: string[];
|
|
810
790
|
arbiter?: string;
|
|
811
791
|
env?: NodeJS.ProcessEnv;
|
|
812
792
|
note?: (message: string) => void;
|
|
813
793
|
}): Promise<{moved: boolean; reasonNotMoved?: string}> {
|
|
814
|
-
const {cwd, slug, reason, questions, arbiter, env} = params;
|
|
794
|
+
const {cwd, slug, item, reason, questions, arbiter, env} = params;
|
|
815
795
|
const note = params.note ?? (() => {});
|
|
816
796
|
if (!arbiter) {
|
|
817
|
-
// No arbiter handle ⇒ no
|
|
818
|
-
// the human is right there, so this is a recorded no-op (parity
|
|
819
|
-
// local-only
|
|
797
|
+
// No arbiter handle ⇒ no `<arbiter>/main` to surface on. A human local-only
|
|
798
|
+
// `complete`: the human is right there, so this is a recorded no-op (parity
|
|
799
|
+
// with the retired local-only lock amend that wrote nothing cross-machine).
|
|
820
800
|
note(
|
|
821
|
-
`'${slug}' bounced locally (no arbiter) — the stuck reason is not
|
|
822
|
-
'on
|
|
801
|
+
`'${slug}' bounced locally (no arbiter) — the stuck reason is not surfaced ` +
|
|
802
|
+
'on <arbiter>/main (a human is right here).',
|
|
823
803
|
);
|
|
824
804
|
return {moved: true};
|
|
825
805
|
}
|
|
806
|
+
const asNewQuestions: NewQuestion[] | undefined = questions?.map((q) => ({
|
|
807
|
+
question: q,
|
|
808
|
+
kind: 'stuck' as const,
|
|
809
|
+
}));
|
|
826
810
|
try {
|
|
827
|
-
const r = await
|
|
828
|
-
item: `task:${slug}`,
|
|
829
|
-
reason,
|
|
830
|
-
questions,
|
|
811
|
+
const r = await surfaceStuckToNeedsAttention({
|
|
831
812
|
cwd,
|
|
813
|
+
slug,
|
|
814
|
+
item,
|
|
815
|
+
reason,
|
|
816
|
+
questions: asNewQuestions,
|
|
832
817
|
arbiter,
|
|
833
818
|
env,
|
|
819
|
+
note,
|
|
834
820
|
});
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
821
|
+
if (r.surfaced) {
|
|
822
|
+
note(`Surfaced '${item}' on ${arbiter}/main (stuck): ${reason}`);
|
|
823
|
+
return {moved: true};
|
|
824
|
+
}
|
|
825
|
+
if (r.bodyAbsent) {
|
|
826
|
+
note(
|
|
827
|
+
`'${item}' has no body on ${arbiter}/main — surface skipped as a clean ` +
|
|
828
|
+
'no-op; the lock was still released to avoid a dead-end held lock.',
|
|
829
|
+
);
|
|
842
830
|
return {moved: true};
|
|
843
831
|
}
|
|
844
832
|
const reasonNotMoved =
|
|
845
|
-
r.
|
|
846
|
-
|
|
847
|
-
'the stuck state — the item is not lock-held).'
|
|
848
|
-
: `could not mark the per-item lock for '${slug}' stuck (${r.outcome}: ` +
|
|
849
|
-
`${r.message}).`;
|
|
833
|
+
r.reasonNotSurfaced ??
|
|
834
|
+
`could not surface '${item}' on ${arbiter}/main (unknown reason).`;
|
|
850
835
|
note(reasonNotMoved);
|
|
851
836
|
return {moved: false, reasonNotMoved};
|
|
852
837
|
} catch (err) {
|
|
853
838
|
const reasonNotMoved =
|
|
854
|
-
`could not
|
|
839
|
+
`could not surface '${item}' on ${arbiter}/main ` +
|
|
855
840
|
`(${err instanceof Error ? err.message : String(err)}).`;
|
|
856
841
|
note(reasonNotMoved);
|
|
857
842
|
return {moved: false, reasonNotMoved};
|
package/src/lifecycle-gather.ts
CHANGED
|
@@ -136,9 +136,27 @@ export function gatherLifecycleInPlace(input: {
|
|
|
136
136
|
repoPath: string;
|
|
137
137
|
read?: LedgerReadStrategy;
|
|
138
138
|
gates?: LifecyclePoolGates;
|
|
139
|
+
/**
|
|
140
|
+
* The HELD TASK slugs to SUBTRACT from the triage/surface/apply candidate
|
|
141
|
+
* inputs before {@link buildLifecyclePools} routes them (task
|
|
142
|
+
* `in-place-scan-subtracts-held-locked-slugs-from-propose-matrix`).
|
|
143
|
+
*
|
|
144
|
+
* Symmetric to the pool-side subtraction `scoreItems` already runs on
|
|
145
|
+
* `state.ready`: without it, a `needsAnswers` TASK whose per-item lock is
|
|
146
|
+
* currently held (state `active`/`stuck`) still slips into the surface / apply
|
|
147
|
+
* pool, so `scan --json` enumerates a matrix leg for it that then always loses
|
|
148
|
+
* the claim CAS (`claim-cas.ts:127-132`) — reddening the propose tick every
|
|
149
|
+
* cadence for as long as the item is held. Narrowly TASK-scoped (this is what
|
|
150
|
+
* {@link heldTaskSlugs} returns): an observation triage entry / a spec surface
|
|
151
|
+
* entry is NOT filtered here, because the lock ref prefix `task-<slug>` only
|
|
152
|
+
* gates the task namespace. Defaults empty (byte-identical to pre-fix
|
|
153
|
+
* behaviour) so callers who cannot resolve a lock read still work.
|
|
154
|
+
*/
|
|
155
|
+
heldSlugs?: Set<string>;
|
|
139
156
|
}): SelectedLifecyclePools {
|
|
140
157
|
const read = input.read ?? ledgerRead;
|
|
141
158
|
const repoPath = input.repoPath;
|
|
159
|
+
const heldSlugs = input.heldSlugs ?? new Set<string>();
|
|
142
160
|
|
|
143
161
|
const rawObservations = read.resolveLocalState({repoPath}).observations;
|
|
144
162
|
const observations: ObservationCandidate[] = rawObservations.map((obs) => ({
|
|
@@ -151,12 +169,17 @@ export function gatherLifecycleInPlace(input: {
|
|
|
151
169
|
read,
|
|
152
170
|
repoPath,
|
|
153
171
|
surfaceStaging,
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
172
|
+
)
|
|
173
|
+
// Held-slug subtraction (task-scoped): a `needsAnswers` TASK whose per-item
|
|
174
|
+
// lock is currently held is EXCLUDED from surface/apply enumeration. Spec /
|
|
175
|
+
// observation entries are untouched — the lock ref set here is task-only.
|
|
176
|
+
.filter((item) => !(item.namespace === 'task' && heldSlugs.has(item.slug)))
|
|
177
|
+
.map((item) => ({
|
|
178
|
+
repoPath,
|
|
179
|
+
namespace: item.namespace,
|
|
180
|
+
slug: item.slug,
|
|
181
|
+
sidecar: readSidecarInPlace(repoPath, item.namespace, item.slug),
|
|
182
|
+
}));
|
|
160
183
|
|
|
161
184
|
return buildLifecyclePools({
|
|
162
185
|
repoPath,
|
package/src/lifecycle-pools.ts
CHANGED
|
@@ -24,9 +24,13 @@ import type {LifecycleSelectedItem} from './select-priority.js';
|
|
|
24
24
|
* **Three lifecycle sub-pools, gated by PURPOSE (ADR `ci-config-policy-and-gate-
|
|
25
25
|
* family.md` \u00a74 \u2014 gates govern CREATE only; CONSUME is always-on):**
|
|
26
26
|
*
|
|
27
|
-
* - **triage** \u2014 UNTRIAGED observations (no `triaged:` settled marker)
|
|
28
|
-
* act (the bot mints
|
|
29
|
-
* {@link LifecyclePoolGates.triage} (the future `observationTriage`
|
|
27
|
+
* - **triage** \u2014 UNTRIAGED observations (no `triaged:` settled marker) with NO
|
|
28
|
+
* sidecar yet. A CREATE act (the bot mints the deterministic triage question),
|
|
29
|
+
* so gated by {@link LifecyclePoolGates.triage} (the future `observationTriage`
|
|
30
|
+
* gate). Like SURFACE, a PENDING sidecar is NOT enumerated (already surfaced +
|
|
31
|
+
* awaiting the human, so re-enumerating only re-spawns the additive surface
|
|
32
|
+
* agent for a no-outcome no-op); it re-enters only when ANSWERED (to apply) or
|
|
33
|
+
* settled by a `triaged:` marker.
|
|
30
34
|
* - **surface** \u2014 `needsAnswers`-blocked tasks/prds with NO all-answered sidecar
|
|
31
35
|
* (no sidecar yet, or a still-pending one). A CREATE act (the bot mints the
|
|
32
36
|
* blocker question), so gated by {@link LifecyclePoolGates.surface} (the future
|
|
@@ -80,6 +84,39 @@ export interface LifecyclePoolGates {
|
|
|
80
84
|
* default is `true`). Spec `staging-surface-and-apply-promote-safety` F2.
|
|
81
85
|
* BUILD/claim eligibility is UNCHANGED in either mode — staging items stay
|
|
82
86
|
* non-claimable, the trust model is untouched.
|
|
87
|
+
*
|
|
88
|
+
* CREATE-vs-CONSUME EDGE (accepted, spec
|
|
89
|
+
* `staging-surface-and-apply-promote-safety` F2 follow-up): `surfaceStaging`
|
|
90
|
+
* gates the CREATE half (surface-side ENUMERATION of staged candidates).
|
|
91
|
+
* APPLY (the consume half) reads through the SAME enumeration, so flipping
|
|
92
|
+
* `surfaceStaging` true→false AFTER a surface tick has minted+answered a
|
|
93
|
+
* staged sidecar can STRAND that sidecar in staging until the flag is flipped
|
|
94
|
+
* back on. The realistic flip direction is off→on (opt-in widening), and an
|
|
95
|
+
* answered staged sidecar only exists if surfacing (opt-in) minted it, so the
|
|
96
|
+
* strand window is narrow and accepted. Revisit only if the create-vs-consume
|
|
97
|
+
* invariant must hold strictly (e.g. re-route `apply` to consume regardless of
|
|
98
|
+
* the surface gate).
|
|
99
|
+
*
|
|
100
|
+
* ## Decisions (ratified by task
|
|
101
|
+
* `f2-mirror-path-staging-test-and-ratify-decisions`, follow-up to slice
|
|
102
|
+
* `f2-surface-staging-config-and-pool-extension` — gate-2 review nits)
|
|
103
|
+
*
|
|
104
|
+
* 1. **Split default is intentional.** `LifecyclePoolGates.surfaceStaging`
|
|
105
|
+
* defaults `false` at the library boundary; `Config.surfaceStaging` defaults
|
|
106
|
+
* `true` at the user-visible layer. The calm library default is load-bearing
|
|
107
|
+
* for any direct caller of `gatherLifecycle*` that does NOT thread CLI gates
|
|
108
|
+
* — they get pool-only behaviour by default and opt IN to staging.
|
|
109
|
+
* 2. **Four new public methods on `LedgerReadStrategy` are intentional**
|
|
110
|
+
* (`resolveLocalTaskStaging`, `resolveLocalSpecStaging`,
|
|
111
|
+
* `resolveMirrorTaskStaging`, `resolveMirrorSpecStaging`), rather than
|
|
112
|
+
* overloading `resolveLocalState` / `resolveMirrorState` with a flag. Keeps
|
|
113
|
+
* the state vs. staging axes orthogonal at the interface.
|
|
114
|
+
* 3. **The `surfaceStaging` gate is consumed by the GATHER, not by pure
|
|
115
|
+
* `buildLifecyclePools`,** even though the field lives on
|
|
116
|
+
* `LifecyclePoolGates`. Placement acknowledged above; ratified as intentional
|
|
117
|
+
* so the gate colocates with its sibling create-side gates.
|
|
118
|
+
* 4. **`surfaceStaging` in `REPO_ALLOWED_KEYS` is intentional** so a repo's
|
|
119
|
+
* `.dorfl.json` can flip it via the normal resolution chain.
|
|
83
120
|
*/
|
|
84
121
|
surfaceStaging?: boolean;
|
|
85
122
|
}
|
|
@@ -201,23 +238,44 @@ export function buildLifecyclePools(
|
|
|
201
238
|
// with the triage create-gate off (the create-vs-consume invariant, ADR
|
|
202
239
|
// `ci-config-policy-and-gate-family` §4). An answered sidecar wins even
|
|
203
240
|
// when the observation body also carries a `triaged:` marker: a human's
|
|
204
|
-
// answer must never be stranded (
|
|
241
|
+
// answer must never be stranded (ADR
|
|
242
|
+
// `answered-observation-sidecar-dominates-triaged-marker.md`).
|
|
205
243
|
apply.push({
|
|
206
244
|
repoPath: input.repoPath,
|
|
207
245
|
slug: obs.slug,
|
|
208
246
|
namespace: 'observation',
|
|
209
247
|
});
|
|
210
|
-
} else if (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
248
|
+
} else if (
|
|
249
|
+
obs.triaged === undefined &&
|
|
250
|
+
obs.sidecar === undefined &&
|
|
251
|
+
triageOn
|
|
252
|
+
) {
|
|
253
|
+
// CREATE (mint the deterministic triage question) — gated by
|
|
254
|
+
// `observationTriage`. ONLY an untriaged observation with NO sidecar yet is
|
|
255
|
+
// a triage candidate: it has never been surfaced. A PENDING sidecar (surfaced
|
|
256
|
+
// already, awaiting the human's answer) is DELIBERATELY DROPPED here — mirror
|
|
257
|
+
// of the SURFACE pool. The triage question is DETERMINISTIC (engine-built) +
|
|
258
|
+
// already present, so re-enumerating a pending observation every tick would
|
|
259
|
+
// only re-run a leg + re-spawn the additive surface agent for a NO-OUTCOME
|
|
260
|
+
// no-op (the persist appends no duplicate). It re-enters only when it is
|
|
261
|
+
// ANSWERED (→ apply, above) or a `triaged:` marker settles it. This is the
|
|
262
|
+
// enumerate-smartness fix: do NOT re-evaluate items that produce no outcome.
|
|
214
263
|
triage.push({
|
|
215
264
|
repoPath: input.repoPath,
|
|
216
265
|
slug: obs.slug,
|
|
217
266
|
namespace: 'observation',
|
|
218
267
|
});
|
|
268
|
+
} else if (obs.triaged !== undefined) {
|
|
269
|
+
// EXPLICIT DROP: SETTLED (`triaged:` non-empty) with no answered sidecar
|
|
270
|
+
// — deliberately NOT enumerated. A pending sidecar on a settled
|
|
271
|
+
// observation would only no-op if re-enumerated, and a settled body is
|
|
272
|
+
// already resolved on the create side (ADR
|
|
273
|
+
// `answered-observation-sidecar-dominates-triaged-marker.md`). Codified
|
|
274
|
+
// as an explicit branch so a future reader does not resurface this cell.
|
|
275
|
+
continue;
|
|
219
276
|
}
|
|
220
|
-
// else:
|
|
277
|
+
// else: UNTRIAGED with no answered sidecar + triage gate OFF — implicit
|
|
278
|
+
// drop (the gate deliberately silences the pool).
|
|
221
279
|
}
|
|
222
280
|
|
|
223
281
|
// --- surface / apply: split `needsAnswers` items by sidecar answered-state ---
|