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/integration-core.ts
CHANGED
|
@@ -313,8 +313,8 @@ export interface IntegrationCoreInput {
|
|
|
313
313
|
// like a normal build.
|
|
314
314
|
source: 'tasks-ready' | 'tasks-backlog' | 'in-progress' | 'done';
|
|
315
315
|
/**
|
|
316
|
-
* Vestigial: was `true` when completing FROM `
|
|
317
|
-
* recovery finish under the legacy folder model). The per-item-lock cutover
|
|
316
|
+
* Vestigial: was `true` when completing FROM the retired `needs-attention/`
|
|
317
|
+
* folder (a recovery finish under the legacy folder model). The per-item-lock cutover
|
|
318
318
|
* (`cutover-needs-attention-becomes-lock-stuck-recovery-surface`) retired
|
|
319
319
|
* that folder — a stuck item is now the lock `state: stuck` and the body
|
|
320
320
|
* stays in `tasks/ready/`, so a recovery `complete` is structurally a normal
|
|
@@ -579,9 +579,11 @@ export interface IntegrationCoreResult {
|
|
|
579
579
|
/** What the core resolved (the tail maps this 1:1 onto its own outcome). */
|
|
580
580
|
outcome: IntegrationCoreOutcome;
|
|
581
581
|
/**
|
|
582
|
-
* True iff a FAILURE outcome was routed
|
|
583
|
-
*
|
|
584
|
-
*
|
|
582
|
+
* True iff a FAILURE outcome was routed through the shared needs-attention
|
|
583
|
+
* mechanism — post lock-cutover, the per-item lock was amended to
|
|
584
|
+
* `state: stuck` with the reason on the lock entry (no folder move). False
|
|
585
|
+
* on the success path and when a failure was NOT surfaced (e.g. a red
|
|
586
|
+
* re-gate that stays put in recovery).
|
|
585
587
|
*/
|
|
586
588
|
routedToNeedsAttention: boolean;
|
|
587
589
|
/** The work branch that was processed (`work/<slug>`). */
|
|
@@ -687,6 +689,19 @@ export async function performIntegration(
|
|
|
687
689
|
recoveryRebaseJitterMs: input.recoveryRebaseJitterMs,
|
|
688
690
|
recoveryRebaseSleep: input.recoveryRebaseSleep,
|
|
689
691
|
recoveryRebaseRandom: input.recoveryRebaseRandom,
|
|
692
|
+
// GATE-2 REVIEW on the recovery path (task
|
|
693
|
+
// `committed-recovery-always-reviews`): a stranded already-complete
|
|
694
|
+
// branch is NOT "already reviewed" — its earlier attempt's PR never
|
|
695
|
+
// merged and Gate 2 may never have run on it. So when `review` is on we
|
|
696
|
+
// MUST run Gate 2 on the rebased tip here too (the SAME reasoning that
|
|
697
|
+
// forces the re-verify: `<arbiter>/main` moved, the merged tree is new).
|
|
698
|
+
// Pass the whole `input` so the recovery tail can call `runGate2Review`
|
|
699
|
+
// with the identical gate/model/watch/round wiring the build path uses.
|
|
700
|
+
input,
|
|
701
|
+
// PR BODY on the recovery path: the recovery has NO fresh agent output
|
|
702
|
+
// (no rebuild), so carry whatever `body` the caller supplied so the PR
|
|
703
|
+
// gets a description instead of degrading to a blank `gh --fill`.
|
|
704
|
+
body: input.body,
|
|
690
705
|
// Answered-merge land (task `committed-recovery-honours-fresh-worktree-gate`,
|
|
691
706
|
// spec `land-time-reverify-and-parallel-merge-ceiling`): the apply-rung
|
|
692
707
|
// dispatches an answered `merge` through this committed-recovery tail (the
|
|
@@ -740,7 +755,7 @@ export async function performIntegration(
|
|
|
740
755
|
// passes no flag, so there an untrusted-origin task RELIABLY forces propose.
|
|
741
756
|
//
|
|
742
757
|
// SCOPE: the task BUILD transition ONLY. It NEVER fires for a `lifecycle`
|
|
743
|
-
// transition (tasking / intake-emit — a
|
|
758
|
+
// transition (tasking / intake-emit — a spec/task FILE landing on main is inert;
|
|
744
759
|
// intake's OWN per-emit resolver already decided that mode), and the source file
|
|
745
760
|
// here is the task being built. A `trusted`/unset task ⇒ untouched (zero
|
|
746
761
|
// behaviour change for the normal human path).
|
|
@@ -793,10 +808,11 @@ export async function performIntegration(
|
|
|
793
808
|
}
|
|
794
809
|
if (!prep.passed) {
|
|
795
810
|
const reason = `prepare (env-prep) failed (exit ${prep.exitCode})`;
|
|
796
|
-
//
|
|
797
|
-
//
|
|
798
|
-
//
|
|
799
|
-
//
|
|
811
|
+
// Mark the item stuck on its per-item lock (the SAME seam a red gate uses)
|
|
812
|
+
// — recording the prepare-failed reason on the lock entry + saving the
|
|
813
|
+
// agent's uncommitted work as a wip commit (post lock-cutover: a lock amend,
|
|
814
|
+
// no `in-progress/ → needs-attention/` folder move). We NEVER run `verify`
|
|
815
|
+
// on an env that could not be made ready.
|
|
800
816
|
const routed = await ledgerWrite.applyNeedsAttentionTransition({
|
|
801
817
|
cwd,
|
|
802
818
|
slug,
|
|
@@ -810,10 +826,10 @@ export async function performIntegration(
|
|
|
810
826
|
routedToNeedsAttention: routed.moved,
|
|
811
827
|
branch,
|
|
812
828
|
reason: routed.moved
|
|
813
|
-
? `Env-prep (prepare) failed (exit ${prep.exitCode});
|
|
814
|
-
'
|
|
829
|
+
? `Env-prep (prepare) failed (exit ${prep.exitCode}); marked '${slug}' ` +
|
|
830
|
+
'stuck on its per-item lock (the environment could not be made ready, ' +
|
|
815
831
|
'so the acceptance gate was NOT run). Fix the prepare command, then ' +
|
|
816
|
-
'
|
|
832
|
+
'`requeue` to release the stuck lock.'
|
|
817
833
|
: `Env-prep (prepare) failed (exit ${prep.exitCode}); not completing ` +
|
|
818
834
|
`'${slug}' (the environment could not be made ready, so the ` +
|
|
819
835
|
'acceptance gate was NOT run). Fix the prepare command, then retry.',
|
|
@@ -832,12 +848,12 @@ export async function performIntegration(
|
|
|
832
848
|
note('Running the acceptance gate (verify)…');
|
|
833
849
|
const gate = await runVerify({cwd, verify: input.verify, env});
|
|
834
850
|
if (!gate.passed) {
|
|
835
|
-
// Don't leave the item dangling
|
|
836
|
-
//
|
|
837
|
-
//
|
|
838
|
-
//
|
|
839
|
-
//
|
|
840
|
-
//
|
|
851
|
+
// Don't leave the item dangling: mark it stuck on its per-item lock with
|
|
852
|
+
// the reason (ADR §12) THROUGH the ledger write seam's needs-attention
|
|
853
|
+
// transition. Post lock-cutover this is a lock amend (`state: stuck` + the
|
|
854
|
+
// reason on the lock entry, no `in-progress/ → needs-attention/` folder
|
|
855
|
+
// move) plus saving the agent's uncommitted work as a wip commit. No
|
|
856
|
+
// partial state.
|
|
841
857
|
const reason = `acceptance gate failed (exit ${gate.exitCode})`;
|
|
842
858
|
const routed = await ledgerWrite.applyNeedsAttentionTransition({
|
|
843
859
|
cwd,
|
|
@@ -860,9 +876,9 @@ export async function performIntegration(
|
|
|
860
876
|
routedToNeedsAttention: routed.moved,
|
|
861
877
|
branch,
|
|
862
878
|
reason: routed.moved
|
|
863
|
-
? `Acceptance gate failed (exit ${gate.exitCode});
|
|
864
|
-
'
|
|
865
|
-
'
|
|
879
|
+
? `Acceptance gate failed (exit ${gate.exitCode}); marked '${slug}' ` +
|
|
880
|
+
'stuck on its per-item lock (surfaced by status; `requeue` once ' +
|
|
881
|
+
'resolved). Fix the work, or use --skip-verify to override.'
|
|
866
882
|
: `Acceptance gate failed (exit ${gate.exitCode}); not completing ` +
|
|
867
883
|
`'${slug}'. Fix the work, or use --skip-verify to override.`,
|
|
868
884
|
};
|
|
@@ -1038,16 +1054,14 @@ export async function performIntegration(
|
|
|
1038
1054
|
// 4. Rebase-before-integrate (ADR §10): rebase the work branch onto the
|
|
1039
1055
|
// latest <arbiter>/main. Clean → continue. Conflict → abort + stop.
|
|
1040
1056
|
//
|
|
1041
|
-
// RECOVERY reconciliation:
|
|
1042
|
-
//
|
|
1043
|
-
//
|
|
1044
|
-
//
|
|
1045
|
-
//
|
|
1046
|
-
//
|
|
1047
|
-
//
|
|
1048
|
-
//
|
|
1049
|
-
// needs-attention/). The done-move thus SUPERSEDES the surfaced state — no
|
|
1050
|
-
// leftover/conflicting on-`main` surface for the human to resolve.
|
|
1057
|
+
// RECOVERY reconciliation: post the per-item-lock cut-over, a stuck item's
|
|
1058
|
+
// body never moved into a `needs-attention/` folder (stuck is the lock
|
|
1059
|
+
// `state: stuck`; the body rests in `backlog/`), so a recovery `complete`'s
|
|
1060
|
+
// kept branch carries NO historical `in-progress → needs-attention`
|
|
1061
|
+
// move-only commit to drop and `<arbiter>/main` holds no surface move to
|
|
1062
|
+
// conflict with. The old recovery drop (`rebaseDroppingNeedsAttentionSurface`,
|
|
1063
|
+
// drop-bookkeeping-rebase) is deleted; recovery is now the SAME plain replay
|
|
1064
|
+
// onto `<arbiter>/main` as any other build (see the plain-rebase note below).
|
|
1051
1065
|
// Fetch the arbiter's `main` into the `<arbiter>/main` remote-tracking ref
|
|
1052
1066
|
// EXPLICITLY. A `run` JOB WORKTREE is cut from a bare hub mirror whose remote
|
|
1053
1067
|
// has no fetch refspec (so `<arbiter>/main` would not otherwise resolve / would
|
|
@@ -1209,12 +1223,12 @@ export async function performIntegration(
|
|
|
1209
1223
|
// recovery above can fall through to integrate while a genuine code conflict
|
|
1210
1224
|
// still routes here.
|
|
1211
1225
|
async function rebaseConflictRoute(): Promise<IntegrationCoreResult> {
|
|
1212
|
-
// Then
|
|
1213
|
-
// §12) THROUGH the ledger write seam's needs-attention transition,
|
|
1214
|
-
// than leaving it dangling
|
|
1215
|
-
//
|
|
1216
|
-
//
|
|
1217
|
-
//
|
|
1226
|
+
// Then mark the item stuck on its per-item lock with the conflict reason
|
|
1227
|
+
// (ADR §12) THROUGH the ledger write seam's needs-attention transition,
|
|
1228
|
+
// rather than leaving it dangling. Post lock-cutover this is a lock amend
|
|
1229
|
+
// (`state: stuck` + the reason on the lock entry, no `done/ →
|
|
1230
|
+
// needs-attention/` folder move); the done-move already committed above
|
|
1231
|
+
// stands. No partial state.
|
|
1218
1232
|
const reason = `rebase onto ${arbiter}/main conflicted (aborted, never auto-resolved)`;
|
|
1219
1233
|
const routed = await ledgerWrite.applyNeedsAttentionTransition({
|
|
1220
1234
|
cwd,
|
|
@@ -1236,9 +1250,9 @@ export async function performIntegration(
|
|
|
1236
1250
|
commitMessage,
|
|
1237
1251
|
reason: routed.moved
|
|
1238
1252
|
? `Rebasing ${branch} onto ${arbiter}/main conflicted; the rebase was ` +
|
|
1239
|
-
`aborted (never auto-resolved) and '${slug}' was
|
|
1240
|
-
'
|
|
1241
|
-
'
|
|
1253
|
+
`aborted (never auto-resolved) and '${slug}' was marked stuck on ` +
|
|
1254
|
+
'its per-item lock (surfaced by status). Resolve against the latest ' +
|
|
1255
|
+
'main, then `requeue` to release the stuck lock and re-run.'
|
|
1242
1256
|
: `Rebasing ${branch} onto ${arbiter}/main conflicted; the rebase was ` +
|
|
1243
1257
|
'aborted (never auto-resolved). Resolve against the latest main, ' +
|
|
1244
1258
|
'then re-run complete.',
|
|
@@ -1318,9 +1332,9 @@ export async function performIntegration(
|
|
|
1318
1332
|
branch,
|
|
1319
1333
|
commitMessage,
|
|
1320
1334
|
reason: routed.moved
|
|
1321
|
-
? `${what} on the rebased tip;
|
|
1322
|
-
'
|
|
1323
|
-
'
|
|
1335
|
+
? `${what} on the rebased tip; marked '${slug}' stuck on its ` +
|
|
1336
|
+
'per-item lock (surfaced by status; `requeue` once resolved). ' +
|
|
1337
|
+
'Fix the work, or use --skip-verify to override.'
|
|
1324
1338
|
: `${what} on the rebased tip; not completing '${slug}'. Fix the ` +
|
|
1325
1339
|
'work, or use --skip-verify to override.',
|
|
1326
1340
|
};
|
|
@@ -1335,7 +1349,8 @@ export async function performIntegration(
|
|
|
1335
1349
|
if (gated.review) {
|
|
1336
1350
|
if (gated.review.kind === 'blocked') {
|
|
1337
1351
|
// The done-move was already committed (steps 2–3), so the slug sits in
|
|
1338
|
-
// work/done/; the routing
|
|
1352
|
+
// work/done/; the routing marked it stuck on its per-item lock (post
|
|
1353
|
+
// lock-cutover — a lock amend, no folder move).
|
|
1339
1354
|
return gated.review.result;
|
|
1340
1355
|
}
|
|
1341
1356
|
approvedVerdict = gated.review.verdict;
|
|
@@ -1503,9 +1518,10 @@ export async function performIntegration(
|
|
|
1503
1518
|
commitMessage,
|
|
1504
1519
|
reason: routed.moved
|
|
1505
1520
|
? `Integrating ${branch} onto ${arbiter}/main kept hitting a ` +
|
|
1506
|
-
`non-fast-forward push (a sibling advanced main); '${slug}' was
|
|
1507
|
-
`
|
|
1508
|
-
`latest main, then
|
|
1521
|
+
`non-fast-forward push (a sibling advanced main); '${slug}' was ` +
|
|
1522
|
+
`marked stuck on its per-item lock (surfaced by status). Resolve ` +
|
|
1523
|
+
`against the latest main, then \`requeue\` to release the stuck ` +
|
|
1524
|
+
`lock and re-run.`
|
|
1509
1525
|
: `Integrating ${branch} onto ${arbiter}/main kept hitting a ` +
|
|
1510
1526
|
`non-fast-forward push (a sibling advanced main). Resolve against the ` +
|
|
1511
1527
|
`latest main, then re-run complete.`,
|
|
@@ -1590,7 +1606,7 @@ export async function performIntegration(
|
|
|
1590
1606
|
* primitive the build path uses.
|
|
1591
1607
|
*
|
|
1592
1608
|
* RE-GATE on the REBASED TIP (task `committed-recovery-honours-fresh-worktree-
|
|
1593
|
-
* gate`,
|
|
1609
|
+
* gate`, spec `land-time-reverify-and-parallel-merge-ceiling`): when the caller
|
|
1594
1610
|
* sets `freshWorktreeGate` (and not `skipVerify`), the EXISTING
|
|
1595
1611
|
* `runFreshWorktreeGate` runs on the rebased tip AFTER the rebase loop and
|
|
1596
1612
|
* BEFORE `applyCompleteTransition`, mirroring the build path's
|
|
@@ -1653,6 +1669,23 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1653
1669
|
prepare?: VerifyConfig;
|
|
1654
1670
|
/** Acceptance gate config for the fresh gate (mirrors the build path). */
|
|
1655
1671
|
verify?: VerifyConfig;
|
|
1672
|
+
/**
|
|
1673
|
+
* The full integration input, threaded so the recovery tail can run Gate 2
|
|
1674
|
+
* (`runGate2Review`) with the identical gate/model/watch/round wiring the
|
|
1675
|
+
* build path uses (task `committed-recovery-always-reviews`). Gate 2 runs on
|
|
1676
|
+
* the rebased tip when `input.review` is on and the fresh gate ran green — a
|
|
1677
|
+
* stranded already-complete branch is NOT trusted as already-reviewed (its
|
|
1678
|
+
* earlier attempt never merged). Optional so the pre-existing non-review
|
|
1679
|
+
* callers (and tests) that do not thread it stay byte-identical.
|
|
1680
|
+
*/
|
|
1681
|
+
input?: IntegrationCoreInput;
|
|
1682
|
+
/**
|
|
1683
|
+
* The propose-mode PR BODY (task `committed-recovery-always-reviews`): the
|
|
1684
|
+
* recovery has NO fresh agent output (no rebuild), so the caller passes
|
|
1685
|
+
* whatever advisory body it has so the PR carries a description instead of a
|
|
1686
|
+
* blank `gh --fill`. Undefined ⇒ today's `--fill` fallback.
|
|
1687
|
+
*/
|
|
1688
|
+
body?: string;
|
|
1656
1689
|
/**
|
|
1657
1690
|
* Autonomous needs-attention surface (mirrors the build path): when set, a
|
|
1658
1691
|
* red rebased-tip gate cherry-picks the bounce onto `main` + pushes the
|
|
@@ -1704,6 +1737,14 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1704
1737
|
// (`isAncestor` is the SAME reachability predicate `gc.ts` uses; do not fork it.)
|
|
1705
1738
|
// KEPT before the retry loop: a no-op MUST short-circuit before we burn any
|
|
1706
1739
|
// re-fetch/re-rebase budget.
|
|
1740
|
+
//
|
|
1741
|
+
// DELIBERATELY the RAW ancestry predicate, NOT `isProvablyMergedForReap`
|
|
1742
|
+
// (task `reap-squash-merged-remote-work-branches`, ratified): this is an
|
|
1743
|
+
// integration-IDEMPOTENCY check, not reap-safety. A squash-landed LOOKALIKE
|
|
1744
|
+
// whose tip is NOT genuinely reachable would falsely read "already
|
|
1745
|
+
// integrated" here and skip a needed rebase/re-push. The squash-aware helper
|
|
1746
|
+
// is scoped to reap-safety ONLY; see gc.ts `isProvablyMergedForReap` and
|
|
1747
|
+
// work/notes/observations/reap-squash-helper-scope-2026-07-10.md.
|
|
1707
1748
|
if (isAncestor(cwd, tip, `refs/remotes/${arbiter}/main`, env)) {
|
|
1708
1749
|
const message =
|
|
1709
1750
|
`Nothing to recover for '${slug}': its work branch tip is already on ` +
|
|
@@ -1801,7 +1842,7 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1801
1842
|
}
|
|
1802
1843
|
|
|
1803
1844
|
// FRESH-WORKTREE GATE on the REBASED TIP (task `committed-recovery-honours-
|
|
1804
|
-
// fresh-worktree-gate`,
|
|
1845
|
+
// fresh-worktree-gate`, spec `land-time-reverify-and-parallel-merge-ceiling`):
|
|
1805
1846
|
// when `freshWorktreeGate` is set (the answered-merge land caller) and not
|
|
1806
1847
|
// `--skip-verify`, re-run the acceptance gate on the rebased tip BEFORE we
|
|
1807
1848
|
// integrate, mirroring the build path's `freshWorktreeGate && !skipVerify &&
|
|
@@ -1812,13 +1853,23 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1812
1853
|
// clean-rebase-but-broken merge. With `freshWorktreeGate` UNSET (the original
|
|
1813
1854
|
// stranded-recovery caller, whose pre-strand build already gated) this whole
|
|
1814
1855
|
// block is skipped and behaviour is byte-identical to before.
|
|
1856
|
+
// Carry an approved Gate-2 verdict (when review ran) so its authored `review`
|
|
1857
|
+
// prose is posted as a PR comment AFTER the integrate below — the SAME audit
|
|
1858
|
+
// trail the build path keeps (task `committed-recovery-always-reviews`).
|
|
1859
|
+
let approvedVerdict: ReviewVerdict | undefined;
|
|
1815
1860
|
if (params.freshWorktreeGate && !params.skipVerify) {
|
|
1816
1861
|
const tip = (
|
|
1817
1862
|
await gitSoft(['rev-parse', '--verify', '--quiet', 'HEAD'], cwd, env)
|
|
1818
1863
|
).stdout.trim();
|
|
1819
|
-
//
|
|
1820
|
-
//
|
|
1821
|
-
//
|
|
1864
|
+
// GATE-2 REVIEW callback (task `committed-recovery-always-reviews`): when
|
|
1865
|
+
// `input.review` is on, run Gate 2 on the rebased tip AFTER the green verify
|
|
1866
|
+
// — EXACTLY the build path's fresh-gate `review:` callback. A stranded
|
|
1867
|
+
// already-complete branch is NOT trusted as already-reviewed (its earlier
|
|
1868
|
+
// attempt's PR never merged, and Gate 2 may never have run on it); the same
|
|
1869
|
+
// reasoning that forces the re-verify here (`<arbiter>/main` moved, so the
|
|
1870
|
+
// merged tree is new) forces the re-review. The needs-attention ROUTING
|
|
1871
|
+
// targets `cwd` (the work branch + ledger), identical to the build path.
|
|
1872
|
+
const reviewInput = params.input;
|
|
1822
1873
|
const gated = await runFreshWorktreeGate({
|
|
1823
1874
|
cwd,
|
|
1824
1875
|
commit: tip,
|
|
@@ -1826,6 +1877,19 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1826
1877
|
verify: params.verify,
|
|
1827
1878
|
env,
|
|
1828
1879
|
note,
|
|
1880
|
+
review:
|
|
1881
|
+
reviewInput?.review === true
|
|
1882
|
+
? (reviewCwd) =>
|
|
1883
|
+
runGate2Review({
|
|
1884
|
+
reviewCwd,
|
|
1885
|
+
input: reviewInput,
|
|
1886
|
+
slug,
|
|
1887
|
+
branch,
|
|
1888
|
+
cwd,
|
|
1889
|
+
env,
|
|
1890
|
+
note,
|
|
1891
|
+
})
|
|
1892
|
+
: undefined,
|
|
1829
1893
|
});
|
|
1830
1894
|
if (!gated.passed) {
|
|
1831
1895
|
const outcome: IntegrationCoreOutcome =
|
|
@@ -1851,15 +1915,43 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1851
1915
|
routedToNeedsAttention: routed.moved,
|
|
1852
1916
|
branch,
|
|
1853
1917
|
reason: routed.moved
|
|
1854
|
-
? `${what} on the rebased tip during committed-recovery;
|
|
1855
|
-
`'${slug}'
|
|
1856
|
-
'
|
|
1918
|
+
? `${what} on the rebased tip during committed-recovery; marked ` +
|
|
1919
|
+
`'${slug}' stuck on its per-item lock (surfaced by status; ` +
|
|
1920
|
+
'`requeue` once resolved). Fix the work, or use --skip-verify ' +
|
|
1857
1921
|
'to override.'
|
|
1858
1922
|
: `${what} on the rebased tip during committed-recovery; not ` +
|
|
1859
1923
|
`completing '${slug}'. Fix the work, or use --skip-verify to ` +
|
|
1860
1924
|
'override.',
|
|
1861
1925
|
};
|
|
1862
1926
|
}
|
|
1927
|
+
// GATE-2 REVIEW outcome on the rebased tip: a BLOCK routes to needs-attention
|
|
1928
|
+
// exactly as the build path (only the reviewed tree moved, not the routing).
|
|
1929
|
+
// On APPROVE: carry the verdict for the post-integrate PR comment and write
|
|
1930
|
+
// the per-run non-blocking-nits observation. UNLIKE the build path this branch
|
|
1931
|
+
// integrates the ALREADY-committed kept tip (no upcoming done-move/commit to
|
|
1932
|
+
// sweep the nits file into), so we FOLD the observation into the kept commit
|
|
1933
|
+
// via `commit --amend` — mirroring the build path's fresh-gate amend so the
|
|
1934
|
+
// nits still land in the SAME commit that integrates (no separate commit).
|
|
1935
|
+
if (gated.review) {
|
|
1936
|
+
if (gated.review.kind === 'blocked') {
|
|
1937
|
+
return gated.review.result;
|
|
1938
|
+
}
|
|
1939
|
+
approvedVerdict = gated.review.verdict;
|
|
1940
|
+
const nitsBefore = await stagedCaptureNotes(cwd, env);
|
|
1941
|
+
writeReviewNitsObservation({
|
|
1942
|
+
cwd,
|
|
1943
|
+
slug,
|
|
1944
|
+
findings: gated.review.verdict?.findings ?? [],
|
|
1945
|
+
note,
|
|
1946
|
+
});
|
|
1947
|
+
await gitHard(['add', '-A'], cwd, env);
|
|
1948
|
+
if (!(await nothingStaged(cwd, env))) {
|
|
1949
|
+
const nitsAfter = await stagedCaptureNotes(cwd, env);
|
|
1950
|
+
if (nitsAfter.length > nitsBefore.length) {
|
|
1951
|
+
await gitHard(['commit', '-q', '--amend', '--no-edit'], cwd, env);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1863
1955
|
}
|
|
1864
1956
|
|
|
1865
1957
|
// Integrate the rebased kept commit through the SAME complete-transition
|
|
@@ -1872,12 +1964,27 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1872
1964
|
(params.openPr
|
|
1873
1965
|
? bridgeProvider(params.openPr)
|
|
1874
1966
|
: selectProvider({arbiterUrl: await arbiterUrl(cwd, arbiter, env)}));
|
|
1967
|
+
// PR TITLE + BODY on the recovery path (task `committed-recovery-always-
|
|
1968
|
+
// reviews`): the stranded branch already holds the task in `work/done/`, so
|
|
1969
|
+
// synthesise the SAME single-line `<type>(<slug>): <title>` PR title the build
|
|
1970
|
+
// path does (from the done-resident task file, never agent text) and scaffold
|
|
1971
|
+
// the task-pointer body around the caller-supplied advisory `body`. Undefined
|
|
1972
|
+
// body ⇒ `composeProposeBody` returns undefined ⇒ the provider degrades to
|
|
1973
|
+
// `gh --fill` (no regression); a supplied body gives the PR a real description
|
|
1974
|
+
// instead of the blank one the recovery path used to open.
|
|
1975
|
+
const prTitle = synthesiseProposeTitle({
|
|
1976
|
+
type: (params.input?.type ?? DEFAULT_TYPE).trim() || DEFAULT_TYPE,
|
|
1977
|
+
slug,
|
|
1978
|
+
title: readTaskTitle(workItemPath(cwd, 'done', slug)),
|
|
1979
|
+
});
|
|
1875
1980
|
const integration = await ledgerWrite.applyCompleteTransition({
|
|
1876
1981
|
arbiter,
|
|
1877
1982
|
branch,
|
|
1878
1983
|
mode,
|
|
1879
1984
|
provider,
|
|
1880
1985
|
noPR: params.noPR,
|
|
1986
|
+
title: prTitle,
|
|
1987
|
+
body: composeProposeBody({slug, body: params.body}),
|
|
1881
1988
|
deleteMergedHead: true,
|
|
1882
1989
|
cwd,
|
|
1883
1990
|
env,
|
|
@@ -1889,6 +1996,32 @@ async function recoverAlreadyCommitted(params: {
|
|
|
1889
1996
|
`(absorbed a moving ${arbiter}/main across ${attempt} re-fetch+re-` +
|
|
1890
1997
|
`rebase attempt${attempt === 1 ? '' : 's'}).`,
|
|
1891
1998
|
);
|
|
1999
|
+
// Post the Gate-2 review as a PR comment (task `committed-recovery-always-
|
|
2000
|
+
// reviews`): the SAME post-integrate audit trail the build path keeps — the
|
|
2001
|
+
// approved verdict's authored `review` prose, on the opened PR. Advisory only
|
|
2002
|
+
// (a block never reaches here — it returned above); the same URL/branch
|
|
2003
|
+
// precedence the build path uses (parsed url wins; else a branch-resolved
|
|
2004
|
+
// fallback when a PR opened but its url was unparseable). `postPRComment*`
|
|
2005
|
+
// never throws. A clean no-op in merge mode / push-only propose (no PR).
|
|
2006
|
+
if (approvedVerdict?.review !== undefined) {
|
|
2007
|
+
if (integration.url !== undefined) {
|
|
2008
|
+
const posted = provider.postPRComment({
|
|
2009
|
+
cwd,
|
|
2010
|
+
url: integration.url,
|
|
2011
|
+
body: approvedVerdict.review,
|
|
2012
|
+
env,
|
|
2013
|
+
});
|
|
2014
|
+
note(posted.instruction);
|
|
2015
|
+
} else if (integration.requestOpened) {
|
|
2016
|
+
const posted = provider.postPRCommentOnBranch({
|
|
2017
|
+
cwd,
|
|
2018
|
+
branch,
|
|
2019
|
+
body: approvedVerdict.review,
|
|
2020
|
+
env,
|
|
2021
|
+
});
|
|
2022
|
+
note(posted.instruction);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
1892
2025
|
return {
|
|
1893
2026
|
outcome: 'completed',
|
|
1894
2027
|
routedToNeedsAttention: false,
|
|
@@ -1931,8 +2064,9 @@ function resolveWorkBranch(
|
|
|
1931
2064
|
*
|
|
1932
2065
|
* Carries the {@link slug} so the autonomous-strand surface in `complete.ts`
|
|
1933
2066
|
* (which catches this error in `performComplete`'s outer try/catch, OUTSIDE the
|
|
1934
|
-
* `runComplete` slug scope) can
|
|
1935
|
-
*
|
|
2067
|
+
* `runComplete` slug scope) can mark the item stuck on its per-item lock (post
|
|
2068
|
+
* lock-cutover — the tree-less lock amend, no `in-progress/ → needs-attention/`
|
|
2069
|
+
* folder move) without re-deriving the slug from the error message.
|
|
1936
2070
|
*/
|
|
1937
2071
|
export class IntegrationNothingStaged extends Error {
|
|
1938
2072
|
constructor(
|
|
@@ -2113,8 +2247,8 @@ export function composeProposeBody(input: {
|
|
|
2113
2247
|
* On a review APPROVE that carries ≥1 NON-BLOCKING finding, write ONE per-run
|
|
2114
2248
|
* observation `work/notes/observations/review-nits-<slug>-<YYYY-MM-DD>.md` capturing all
|
|
2115
2249
|
* of this run's non-blocking nits, so they get a durable, contract-native home
|
|
2116
|
-
* instead of evaporating (the block path already
|
|
2117
|
-
*
|
|
2250
|
+
* instead of evaporating (the block path already records BLOCKING findings as the
|
|
2251
|
+
* stuck reason on the item's per-item lock; the approve path dropped non-blocking ones — see
|
|
2118
2252
|
* `work/findings/review-nonblocking-findings-disposition.md`).
|
|
2119
2253
|
*
|
|
2120
2254
|
* The RUNNER writes it (the review agent stays write-free). It is a PLAIN
|
|
@@ -2841,8 +2975,8 @@ async function runGate2Review(params: {
|
|
|
2841
2975
|
});
|
|
2842
2976
|
const message = routed.moved
|
|
2843
2977
|
? `PR/code review (Gate 2) produced an UNPARSEABLE verdict for '${slug}'; ` +
|
|
2844
|
-
'
|
|
2845
|
-
'transient-infra — re-run). NOT integrated.'
|
|
2978
|
+
'marked it stuck on its per-item lock (work branch pushed + lock ' +
|
|
2979
|
+
'surfaced; transient-infra — re-run). NOT integrated.'
|
|
2846
2980
|
: `PR/code review (Gate 2) produced an UNPARSEABLE verdict for '${slug}'; ` +
|
|
2847
2981
|
'NOT integrating.';
|
|
2848
2982
|
note(message);
|
|
@@ -2888,9 +3022,9 @@ async function runGate2Review(params: {
|
|
|
2888
3022
|
note,
|
|
2889
3023
|
});
|
|
2890
3024
|
const message = routed.moved
|
|
2891
|
-
? `PR/code review (Gate 2) blocked '${slug}';
|
|
2892
|
-
'
|
|
2893
|
-
'recorded
|
|
3025
|
+
? `PR/code review (Gate 2) blocked '${slug}'; marked it stuck on its ` +
|
|
3026
|
+
'per-item lock (surfaced by status; the blocking findings are ' +
|
|
3027
|
+
'recorded on the lock entry). NOT integrated.'
|
|
2894
3028
|
: `PR/code review (Gate 2) blocked '${slug}'; NOT integrating.`;
|
|
2895
3029
|
note(message);
|
|
2896
3030
|
return {
|
package/src/integrator.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {IntegrationMode} from './config.js';
|
|
2
2
|
import {git, run} from './git.js';
|
|
3
|
-
import {isAncestor} from './gc.js';
|
|
3
|
+
import {isAncestor, isProvablyMergedForReap} from './gc.js';
|
|
4
|
+
import {parseWorkBranchRef} from './slug-namespace.js';
|
|
5
|
+
import type {SidecarType} from './sidecar.js';
|
|
4
6
|
import type {BackoffOptions, Sleep} from './retry-backoff.js';
|
|
5
7
|
import {pushProposeBranchWithStaleLeaseRetry} from './continue-branch.js';
|
|
6
8
|
|
|
@@ -135,7 +137,7 @@ export interface OpenRequestInput {
|
|
|
135
137
|
* When present a provider passes it verbatim (e.g. `gh pr create --body`)
|
|
136
138
|
* instead of `--fill`'s empty/commit-derived description. Typically the build
|
|
137
139
|
* agent's final summary, optionally under a runner-scaffolded header (a pointer
|
|
138
|
-
* to `work/done/<slug>.md` + the
|
|
140
|
+
* to `work/done/<slug>.md` + the spec/ADR it serves). Absent ⇒ today's `--fill`
|
|
139
141
|
* (no regression). This is the BODY-AT-OPEN surface; a follow-up PR COMMENT is
|
|
140
142
|
* a separate provider method.
|
|
141
143
|
*/
|
|
@@ -681,13 +683,24 @@ function deleteMergedHeadBranch(input: IntegrateInput): void {
|
|
|
681
683
|
);
|
|
682
684
|
const headSha = parseLsRemoteSha(ls.stdout);
|
|
683
685
|
if (headSha !== undefined) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
686
|
+
// Provably-merged-for-reap = fast-path ancestor OR squash-aware fallback
|
|
687
|
+
// (durable done/dropped record on <arbiter>/main + branch carries nothing
|
|
688
|
+
// main lacks). The SAME predicate the `gc.ts` worktree reaper and the
|
|
689
|
+
// `reap-branches.ts` remote sweep use — do not fork it.
|
|
690
|
+
const parsed = parseWorkBranchRef(branch);
|
|
691
|
+
const arbiterMainRef = `refs/remotes/${arbiter}/main`;
|
|
692
|
+
const provablyMerged =
|
|
693
|
+
parsed === undefined
|
|
694
|
+
? isAncestor(input.cwd, headSha, arbiterMainRef, env)
|
|
695
|
+
: isProvablyMergedForReap({
|
|
696
|
+
cwd: input.cwd,
|
|
697
|
+
tip: headSha,
|
|
698
|
+
arbiterMain: arbiterMainRef,
|
|
699
|
+
namespace: parsed.namespace as SidecarType,
|
|
700
|
+
slug: parsed.slug,
|
|
701
|
+
env,
|
|
702
|
+
});
|
|
703
|
+
if (!provablyMerged) {
|
|
691
704
|
return; // NOT provably merged (a racing un-merged amend) — never reap.
|
|
692
705
|
}
|
|
693
706
|
}
|
package/src/isolation.ts
CHANGED
|
@@ -111,11 +111,11 @@ export interface PrepareInput {
|
|
|
111
111
|
/** The work slug being processed (→ branch `work/<type>-<slug>`). */
|
|
112
112
|
slug: string;
|
|
113
113
|
/**
|
|
114
|
-
* The item TYPE — `'task'` for a build (intake/`do task:`), `'
|
|
114
|
+
* The item TYPE — `'task'` for a build (intake/`do task:`), `'spec'` for a
|
|
115
115
|
* spec-tasking run (`do spec:`). It NAMESPACES the work branch via
|
|
116
116
|
* {@link workBranchRef} so a same-slug task and spec never collide on the
|
|
117
117
|
* arbiter branch. Defaults to `'task'` (the overwhelmingly-common build
|
|
118
|
-
* path); the spec-tasking path passes `'
|
|
118
|
+
* path); the spec-tasking path passes `'spec'` explicitly.
|
|
119
119
|
*/
|
|
120
120
|
type?: SlugNamespace;
|
|
121
121
|
/**
|
|
@@ -394,6 +394,15 @@ export function inPlaceStrategy(options: {
|
|
|
394
394
|
* path uses before force-resetting the work branch onto the claim commit. A
|
|
395
395
|
* not-yet-fetched or rolled-back arbiter main that does NOT reach the claim must
|
|
396
396
|
* fail fast here, never silently build on a stale base.
|
|
397
|
+
*
|
|
398
|
+
* DELIBERATELY the RAW `--is-ancestor` predicate, NOT the squash-aware
|
|
399
|
+
* `isProvablyMergedForReap` (task `reap-squash-merged-remote-work-branches`,
|
|
400
|
+
* ratified): this is a claim-REACHABILITY guard, not reap-safety. It demands
|
|
401
|
+
* GENUINE ancestry of the claim commit; a done-record-on-main match would
|
|
402
|
+
* defeat its whole purpose (refusing to build on a stale base). The
|
|
403
|
+
* squash-aware helper is scoped to reap-safety ONLY; this module's reap-lane
|
|
404
|
+
* (`reapJob` → `evaluateDeletionSafety`) is where it belongs. See
|
|
405
|
+
* work/notes/observations/reap-squash-helper-scope-2026-07-10.md.
|
|
397
406
|
*/
|
|
398
407
|
function assertClaimCommitReachable(
|
|
399
408
|
checkout: string,
|