Skip to content

refactor(cutover 1/3): core — IR-driven lifecycle foundation#2341

Merged
gsxdsm merged 5 commits into
mainfrom
cutover/stack-1-core
Jul 19, 2026
Merged

refactor(cutover 1/3): core — IR-driven lifecycle foundation#2341
gsxdsm merged 5 commits into
mainfrom
cutover/stack-1-core

Conversation

@gsxdsm

@gsxdsm gsxdsm commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Part 1 of 3 of the IR-driven lifecycle cutover (split from #2335 to fit review-tool file limits; plan: docs/plans/2026-07-18-001-refactor-ir-driven-lifecycle-cutover-plan.md, included here).

Scope (48 files, packages/core + docs/plans): shared transition policy + validator (KTD-5), IR validation hardening incl. the benchmark capability floor, CAS review leases (KTD-4), pooled WIP capacity budgets (KTD-9), lifecycle-trait helpers, durable IR pin/drift detection (KTD-3), review-level creation-time preset, legacy adoption module + census + migration 0026 + stale-binary guard (KTD-8), core-side builtin workflow fixes (single default-IR authority, no-merge complete-column support).

Note: workflow-cutover.ts (interpreter parity scaffolding) stays alive in this PR — its last consumer dies in part 2/3, which retires it.

Merge order: this PR → #TBD-2 (engine) → #2335 (dashboard/top).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added workflow-trait-driven task lifecycle transitions, including WIP capacity pooling and workflow-aware recovery (IR pinning + drift detection).
    • Added legacy adoption/backfill for pre-cutover task states, with unmappable rows safely parked.
    • Added create-time reviewLevel presets to automatically configure enabled workflow steps.
  • Bug Fixes
    • Fixed workflow moves when no workflow selection exists.
    • Improved merge-blocker validation to be keyed to the workflow’s actual review-lane identity, preventing invalid moves and misclassified terminal states.
  • Tests
    • Added end-to-end and unit/integration coverage for workflow validation, legacy adoption, migrations/schema guards, leases, review presets, and transition rules.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@gsxdsm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 27 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b86b697b-d93c-4ddf-9436-61d9f405a09c

📥 Commits

Reviewing files that changed from the base of the PR and between 92ec988 and 9c5e71c.

📒 Files selected for processing (4)
  • packages/core/src/__tests__/legacy-adoption.test.ts
  • packages/core/src/postgres/schema-applier.ts
  • packages/core/src/task-store/lifecycle-ops.ts
  • packages/core/src/workflow-capacity.ts
📝 Walkthrough

Walkthrough

This change establishes workflow IR as the lifecycle authority, adding trait-based transition policies, default workflow resolution, review leases, workflow pin persistence, legacy-row adoption, schema safeguards, review-level creation presets, and extensive validation and regression coverage.

Changes

Workflow lifecycle cutover

Layer / File(s) Summary
Workflow contracts and policy primitives
packages/core/src/builtin-workflows.ts, packages/core/src/workflow-*.ts, packages/core/src/review-level-preset.ts, packages/core/src/index*.ts
Adds default workflow resolution, trait-based column helpers, pooled WIP budgets, IR validation, drift detection, transition policies, review leases, and public exports.
Task persistence and legacy adoption
packages/core/src/legacy-adoption.ts, packages/core/src/task-store/*, packages/core/src/postgres/*
Persists workflow pins and adoption timestamps, migrates schema version 0027, rejects newer-database writes from older binaries, and sweeps legacy rows during store initialization.
Move integration and workflow creation
packages/core/src/task-store/moves.ts, packages/core/src/task-store/task-creation.ts, packages/core/src/task-merge.ts
Uses the shared default IR and trait-derived transition checks, enforces pooled capacity in backend and SQLite paths, supports custom merge-lane identity, and applies review-level presets at creation time.
Validation and regression coverage
packages/core/src/__tests__/*
Covers adoption completeness, schema upgrades, stale-binary checks, default workflow movement, lifecycle traits, transition invariants, review presets, IR validation, and custom review lanes.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TaskStore
  participant WorkflowResolver
  participant TransitionPolicy
  participant WorkflowDatabase
  TaskStore->>WorkflowResolver: resolve task workflow IR
  WorkflowResolver-->>TaskStore: resolved IR and column traits
  TaskStore->>TransitionPolicy: evaluate transition invariants
  TransitionPolicy-->>TaskStore: allow or rejection
  TaskStore->>WorkflowDatabase: persist move and workflow metadata
Loading

Possibly related PRs

  • Runfusion/Fusion#1490: Adds a workflow-task runtime facade whose workflow IR fallback behavior is affected by the default resolver changes.
  • Runfusion/Fusion#2088: Reworks the PostgreSQL schema baseline and migration tracking touched by the new migration and stale-binary guard.
  • Runfusion/Fusion#2335: Implements closely related IR-driven lifecycle cutover modules, persistence, adoption, and legacy-path changes.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the PR’s core focus on the first cutover phase and the IR-driven lifecycle foundation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cutover/stack-1-core

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR lands the first third of the IR-driven lifecycle cutover — the core foundation layer for packages/core. It introduces the shared transition-policy validator (KTD-5), durable IR pin + drift detection (KTD-3), pooled WIP capacity budgets (KTD-9), workflow-trait helper primitives (KTD-10), a create-time reviewLevel preset (KTD-11), and the legacy-adoption backfill sweep (KTD-8) including a durable drain marker. It also fixes the builtin:coding default-IR authority drift that caused "preflight is stale" on no-selection moves, and corrects the linear builtin's column-assignment to stop unseamed nodes re-entering the hold column mid-flight.

  • Drift detection (workflow-ir-resolver.ts): detectWorkflowDrift stores pin.columnId at entry time specifically to catch a deleted column when the node survives, but the check node.column ?? pin.columnId always resolves to node.column for v2 IRs, so the pinned column is never verified against the current column list. The stated capability is not implemented.
  • Legacy adoption sweep (task-store/lifecycle-ops.ts): pagination, drain marker, idempotency, and userPaused-withhold logic are sound and correctly placed in both backend and SQLite paths.
  • Transition-policy module (workflow-transition-policy.ts): clean pure-function design, well-covered by the new unit tests.
  • Schema + migration (0027): IF NOT EXISTS makes migration idempotent; baseline 0000_initial.sql is updated to keep fresh installs consistent.

Confidence Score: 4/5

Safe to merge with one fix: detectWorkflowDrift in workflow-ir-resolver.ts does not check the pinned (entry-time) column against the current column list when the node itself survives. No recovery sweep calls this function yet in this PR, so there is no immediate runtime breakage, but the defect will be inherited by parts 2/3 where the consumers land.

The drift-detection infrastructure is laid here but its consumers arrive in part 2/3. The pin.columnId field's stated purpose — catching a deleted column even when the node survives — is not implemented: the check always resolves to node.column (the current column), so pin.columnId is unreachable. Parts 2/3 will depend on this function behaving correctly. Everything else — the transition-policy module, legacy adoption sweep, pooled-capacity enforcement, builtin-workflow column fix, and schema migration — is sound and well-tested.

packages/core/src/workflow-ir-resolver.ts — detectWorkflowDrift needs to check pin.columnId against the current columns array independently of node.column.

Important Files Changed

Filename Overview
packages/core/src/workflow-ir-resolver.ts Adds KTD-3 IR pin infrastructure (WorkflowIrPin, hashWorkflowIr, computeWorkflowIrPin, detectWorkflowDrift). detectWorkflowDrift has a logic defect: pin.columnId is never checked against the current column list when node.column is present, defeating its stated purpose of detecting a deleted column while the node survives.
packages/core/src/task-store/lifecycle-ops.ts Store-open legacy adoption sweep (KTD-8): correctly runs in both backend and SQLite paths, paginates, withholds the drain marker when any mutation is planned (including userPaused), and makes adoption idempotent via legacyAdoptedAt. Migration drain marker ties cleanly to the bookkeeping table.
packages/core/src/workflow-transition-policy.ts New pure shared transition validator (KTD-5): merge-blocker and terminal-reentry invariants as return-guard postconditions; capacity verdict separated for in-txn use. Well-designed, no store/engine imports, matches unit tests.
packages/core/src/task-store/moves.ts Wires the shared transition-policy validator, fixes default-IR authority via resolveDefaultWorkflowIr(), and introduces enforcePooledColumnCapacity for both async and sync transaction paths. Correctly excludes moving task from occupant count via excludeTaskId.
packages/core/src/legacy-adoption.ts Adoption table + planLegacyAdoption planner: coverage is complete (census-enforced), idempotency via legacyAdoptedAt is sound. Minor: the backfill-only path reports action: "clear" when nothing is cleared — audit label only, not behavioral.
packages/core/src/builtin-workflows.ts Fixes linear builtin's column assignment for unseamed nodes (inherit instead of hard-code "todo"), adds resolveDefaultWorkflowIr() single authority, and DEFAULT_WORKFLOW_ID constant. Column inheritance logic is correct.
packages/core/src/workflow-capacity.ts Adds resolveWipBudgetColumns for KTD-9 pooled budget resolution. Uses (ir as WorkflowIrV2).columns with an implicit invariant (truthy targetKey proves v2) — safe given current findColumn but not type-guarded.
packages/core/src/postgres/migrations/0027_workflow_ir_pin_and_legacy_adoption.sql Adds workflow_ir_pin*, legacy_adopted_at columns via IF NOT EXISTS — idempotent. Schema applier and baseline updated consistently.
packages/core/src/workflow-lifecycle-traits.ts New pure trait→column primitives (columnsWithFlag, resolveReboundTarget, resolveCompleteColumn, resolveMergeOrchestrationColumn). Clean design, well-tested against builtin:coding and custom workflow shapes.
packages/core/src/review-level-preset.ts KTD-11 creation-time reviewLevel preset: maps numeric level to optional-group ids; explicit enabledWorkflowSteps always wins. Applied at all three creation entry points in task-creation.ts.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph "KTD-3: IR Pin & Drift Detection"
        A[Task enters node] --> B[computeWorkflowIrPin\nirHash + columnId stored]
        B --> C[workflowIrPin persisted to DB]
        C --> D{Restart / recovery}
        D --> E[detectWorkflowDrift\ncurrent IR vs pin]
        E -->|hash matches| F[No drift — resume]
        E -->|node deleted| G[park: reconcile-workflow-drift]
        E -->|column deleted| G
        E -->|hash differs, structure OK| F
    end

    subgraph "KTD-5: Shared Transition Policy"
        H[moveTaskInternalImpl] --> I[resolveTransitionColumnFacts\nfrom + to flags]
        I --> J[evaluateTransitionInvariants\nmerge-blocker + terminal-reentry]
        J -->|allow| K{capacity check\nenforcePooledColumnCapacity}
        J -->|reject| L[TransitionRejectionError]
        K -->|budget OK| M[move committed]
        K -->|exhausted| L
    end

    subgraph "KTD-8: Legacy Adoption Sweep"
        N[store open] --> O{drained marker?}
        O -->|yes| P[skip sweep]
        O -->|no| Q[paginate listTasks]
        Q --> R[planLegacyAdoption\nfor each row]
        R -->|skip / already-adopted| Q
        R -->|resume-graph / clear| S[updateTask status=null]
        R -->|park-paused| T[updateTask paused=true]
        R -->|preserve + backfill| U[updateTask enabledWorkflowSteps]
        S & T & U --> V{mutationPlanned?}
        V -->|no| W[write drained marker]
        V -->|yes| Q
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph "KTD-3: IR Pin & Drift Detection"
        A[Task enters node] --> B[computeWorkflowIrPin\nirHash + columnId stored]
        B --> C[workflowIrPin persisted to DB]
        C --> D{Restart / recovery}
        D --> E[detectWorkflowDrift\ncurrent IR vs pin]
        E -->|hash matches| F[No drift — resume]
        E -->|node deleted| G[park: reconcile-workflow-drift]
        E -->|column deleted| G
        E -->|hash differs, structure OK| F
    end

    subgraph "KTD-5: Shared Transition Policy"
        H[moveTaskInternalImpl] --> I[resolveTransitionColumnFacts\nfrom + to flags]
        I --> J[evaluateTransitionInvariants\nmerge-blocker + terminal-reentry]
        J -->|allow| K{capacity check\nenforcePooledColumnCapacity}
        J -->|reject| L[TransitionRejectionError]
        K -->|budget OK| M[move committed]
        K -->|exhausted| L
    end

    subgraph "KTD-8: Legacy Adoption Sweep"
        N[store open] --> O{drained marker?}
        O -->|yes| P[skip sweep]
        O -->|no| Q[paginate listTasks]
        Q --> R[planLegacyAdoption\nfor each row]
        R -->|skip / already-adopted| Q
        R -->|resume-graph / clear| S[updateTask status=null]
        R -->|park-paused| T[updateTask paused=true]
        R -->|preserve + backfill| U[updateTask enabledWorkflowSteps]
        S & T & U --> V{mutationPlanned?}
        V -->|no| W[write drained marker]
        V -->|yes| Q
    end
Loading

Reviews (4): Last reviewed commit: "Address PR review feedback round 3 (#234..." | Re-trigger Greptile

Comment thread packages/core/src/postgres/postgres-health.ts
Comment thread packages/core/src/legacy-adoption.ts
Comment thread packages/core/src/task-store/moves.ts
Comment thread packages/core/src/__tests__/legacy-adoption.test.ts
gsxdsm added a commit that referenced this pull request Jul 19, 2026
- dedupe workflow_ir_pin_column_id in postgres-health EXPECTED_PROJECT_COLUMNS
- legacy-adoption: 'paused' removed from preserve-comment (task pause is a boolean field, never a status; documented)
- getTaskMergeBlocker gains explicit skipColumnIdentityCheck option; KTD-5 validator passes the REAL task instead of spoofing column:'in-review'
- status-write census recursively scans core+engine+dashboard src with precision-hardened patterns (9 false-positive classes excluded) and a >100-file vacuity floor

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gsxdsm and others added 3 commits July 19, 2026 11:04
Transition policy + shared validator, IR validation hardening, CAS review leases, capacity budgets, lifecycle traits, IR pin/drift, review-level preset, legacy adoption + migration 0026, builtin workflow fixes (core side), and the cutover plan + handoff docs. Stack: 1/3 (base main); engine cutover is 2/3; dashboard + changesets top out in #2335.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- dedupe workflow_ir_pin_column_id in postgres-health EXPECTED_PROJECT_COLUMNS
- legacy-adoption: 'paused' removed from preserve-comment (task pause is a boolean field, never a status; documented)
- getTaskMergeBlocker gains explicit skipColumnIdentityCheck option; KTD-5 validator passes the REAL task instead of spoofing column:'in-review'
- status-write census recursively scans core+engine+dashboard src with precision-hardened patterns (9 false-positive classes excluded) and a >100-file vacuity floor

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…laimed 0026)

Rebased onto main's 0026_bigint_counters (#2331): our migration renumbers to 0027,
SCHEMA_BASELINE_VERSION bumps to 0027, applier re-spliced onto main's reworked file,
fixture/probe versions updated. Note: main's tip itself fails the automation
project-isolation upgrade test (bigint ALTER vs legacy 0000 fixture missing
token_usage_input_tokens) — verified on detached origin/main; not ours.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gsxdsm
gsxdsm force-pushed the cutover/stack-1-core branch from 612bc71 to 419d464 Compare July 19, 2026 18:08
@gsxdsm

gsxdsm commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto latest main and resolved the conflict: main's #2331 claimed migration 0026 (bigint counters), so this PR's IR-pin/legacy-adoption migration renumbered to 0027 with SCHEMA_BASELINE_VERSION bumped to match; the applier delta was re-spliced onto main's reworked schema-applier.

⚠️ Main-inherited test regression worth a separate fix: main's own tip fails schema-applier.test.ts > automation project-isolation > upgrades 0000 rows...#2331's bigint ALTER runs unconditionally against the legacy 0000 fixture, which lacks token_usage_input_tokens (column does not exist). Verified on detached origin/main, unrelated to this stack. It will show as the one red in this suite until fixed on main.

🤖 Generated with Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/task-store/lifecycle-ops.ts (1)

256-268: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Adoption sweep is gated behind unrelated steps' success.

adoptLegacyTaskRowsOnOpen(store) shares this try block with runWorkflowColumnsIntegrityPass() and recoverStaleTransitionPending(). If either of those two throws, the catch swallows it and adoption never runs this boot cycle — even though adoptLegacyTaskRowsOnOpen already has its own internal try/catch and is designed to be independently safe. Given the file's stated goal ("every pre-cutover task row must wake OWNED — no silently frozen rows"), the sweep should not be incidentally skipped by an unrelated failure.

♻️ Suggested fix: give the adoption call its own try boundary
     try {
       await store.runWorkflowColumnsIntegrityPass();
       // `#1401`: recover any transitionPending markers stranded by a crash
       // between the in-txn write and the post-commit clear (they otherwise
       // permanently inflate capacity counts for their target column).
       await store.recoverStaleTransitionPending();
-      await adoptLegacyTaskRowsOnOpen(store);
     } catch (err) {
       storeLog.warn("workflowColumns integrity pass failed during init", {
         phase: "init:workflow-columns-integrity",
         error: err instanceof Error ? err.message : String(err),
       });
     }
+    await adoptLegacyTaskRowsOnOpen(store);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/task-store/lifecycle-ops.ts` around lines 256 - 268,
Separate adoptLegacyTaskRowsOnOpen(store) from the try block containing
runWorkflowColumnsIntegrityPass() and recoverStaleTransitionPending(). Give the
integrity and recovery operations their existing warning boundary, then invoke
adoption under its own try boundary so failures in either unrelated step cannot
skip the adoption sweep, while preserving its internal error handling.
🧹 Nitpick comments (2)
packages/core/src/workflow-capacity.ts (1)

175-185: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify redundant array checks.

Because targetKey is truthy at this stage, we are mathematically guaranteed that resolveColumnBudgetKey successfully located targetColumn using findColumn, which already asserts that (ir as WorkflowIrV2).columns is an array.

Consequently, columns is always iterable and set will always contain at least targetColumn, making the defensive checks and the ternary fallback safely removable.

♻️ Proposed refactor
 export function resolveWipBudgetColumns(ir: WorkflowIr, targetColumn: string): string[] {
   const targetKey = resolveColumnBudgetKey(ir, targetColumn);
   if (!targetKey) return [];
-  const v2 = ir as WorkflowIrV2;
-  const columns = Array.isArray(v2.columns) ? v2.columns : [];
   const set: string[] = [];
-  for (const c of columns) {
+  for (const c of (ir as WorkflowIrV2).columns) {
     if (resolveColumnBudgetKey(ir, c.id) === targetKey) set.push(c.id);
   }
-  return set.length > 0 ? set : [targetColumn];
+  return set;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/workflow-capacity.ts` around lines 175 - 185, In
resolveWipBudgetColumns, rely on the successful targetKey lookup to use (ir as
WorkflowIrV2).columns directly, removing the redundant Array.isArray fallback.
Since targetColumn is guaranteed to be included, return the collected set
directly and remove the length check and targetColumn fallback.
packages/core/src/task-store/lifecycle-ops.ts (1)

271-343: 🚀 Performance & Scalability | 🔵 Trivial

Full active-task sweep runs on every store open indefinitely, not just during the cutover window.

adoptLegacyTaskRowsOnOpen paginates through every active task (500/page) on every single store open, forever — there's no completion marker to short-circuit the sweep once no legacy rows remain. For deployments with large task counts or frequent restarts, this adds a permanent, unbounded (in wall-clock terms) startup cost that scales with total active task count rather than with the shrinking legacy backlog. The offset-pagination rationale documented above is sound for correctness, but nothing here caps the steady-state cost once adoption is fully drained project-wide.

Consider persisting a project-level "legacy adoption complete" marker (set once a full sweep completes with zero adoptions) to skip the sweep entirely on subsequent opens, re-arming it only if needed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/task-store/lifecycle-ops.ts` around lines 271 - 343, Update
adoptLegacyTaskRowsOnOpen to persist and check a project-level legacy-adoption
completion marker before paginating; skip the sweep when the marker is set, and
set it only after a full sweep completes with zero adoptions. Preserve the
existing pagination, per-task adoption, and failure handling, and re-arm or
avoid marking completion when the sweep fails or adopts rows.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/index.gate.ts`:
- Around line 2219-2242: Add the runtime export of StaleBinarySchemaError and
assertBinaryNotOlderThanDatabase to the gate barrel index.gate.ts, mirroring
their existing exports from index.ts. Place them with the other gate-safe barrel
exports and preserve their original source module and export behavior so the
engine-core bundle exposes both symbols.

In `@packages/core/src/task-store/workflow-definitions.ts`:
- Around line 468-482: Wrap the default IR returned by the custom-workflow
fallback branches in store.applyBuiltInPromptOverridesSync, matching the
!workflowId path. Update both the !row branch and the database-read catch
branch, using DEFAULT_WORKFLOW_ID with resolveDefaultWorkflowIr(), while leaving
successful custom-workflow parsing unchanged.

---

Outside diff comments:
In `@packages/core/src/task-store/lifecycle-ops.ts`:
- Around line 256-268: Separate adoptLegacyTaskRowsOnOpen(store) from the try
block containing runWorkflowColumnsIntegrityPass() and
recoverStaleTransitionPending(). Give the integrity and recovery operations
their existing warning boundary, then invoke adoption under its own try boundary
so failures in either unrelated step cannot skip the adoption sweep, while
preserving its internal error handling.

---

Nitpick comments:
In `@packages/core/src/task-store/lifecycle-ops.ts`:
- Around line 271-343: Update adoptLegacyTaskRowsOnOpen to persist and check a
project-level legacy-adoption completion marker before paginating; skip the
sweep when the marker is set, and set it only after a full sweep completes with
zero adoptions. Preserve the existing pagination, per-task adoption, and failure
handling, and re-arm or avoid marking completion when the sweep fails or adopts
rows.

In `@packages/core/src/workflow-capacity.ts`:
- Around line 175-185: In resolveWipBudgetColumns, rely on the successful
targetKey lookup to use (ir as WorkflowIrV2).columns directly, removing the
redundant Array.isArray fallback. Since targetColumn is guaranteed to be
included, return the collected set directly and remove the length check and
targetColumn fallback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 56c2b67d-0998-4909-a670-1b39fc8b83d9

📥 Commits

Reviewing files that changed from the base of the PR and between c0eafc2 and 419d464.

📒 Files selected for processing (47)
  • docs/plans/2026-07-18-001-refactor-ir-driven-lifecycle-cutover-plan.md
  • docs/plans/2026-07-19-001-u5e-executecore-lift-handoff.md
  • docs/plans/2026-07-19-002-u5e-remaining-deletions-handoff.md
  • docs/plans/2026-07-19-003-u5f-workflow-aware-flip-handoff.md
  • docs/plans/2026-07-19-004-u5g-flip-residual-handoff.md
  • docs/plans/2026-07-19-005-u10-flip-residual-handoff.md
  • docs/plans/2026-07-19-006-u10b-post-flip-handoff.md
  • packages/core/src/__tests__/custom-review-lane-merge-blocker.test.ts
  • packages/core/src/__tests__/legacy-adoption.test.ts
  • packages/core/src/__tests__/no-selection-default-workflow-move.test.ts
  • packages/core/src/__tests__/postgres/schema-applier.test.ts
  • packages/core/src/__tests__/review-level-preset.test.ts
  • packages/core/src/__tests__/workflow-ir-validation.test.ts
  • packages/core/src/__tests__/workflow-lifecycle-traits.test.ts
  • packages/core/src/builtin-workflows.ts
  • packages/core/src/index.gate.ts
  • packages/core/src/index.ts
  • packages/core/src/legacy-adoption.ts
  • packages/core/src/postgres/index.ts
  • packages/core/src/postgres/migrations/0000_initial.sql
  • packages/core/src/postgres/migrations/0027_workflow_ir_pin_and_legacy_adoption.sql
  • packages/core/src/postgres/postgres-health.ts
  • packages/core/src/postgres/schema-applier.ts
  • packages/core/src/postgres/schema/project.ts
  • packages/core/src/review-level-preset.ts
  • packages/core/src/store.ts
  • packages/core/src/task-merge.ts
  • packages/core/src/task-store/__tests__/transition-validator.test.ts
  • packages/core/src/task-store/lifecycle-ops.ts
  • packages/core/src/task-store/moves.ts
  • packages/core/src/task-store/persistence.ts
  • packages/core/src/task-store/remaining-ops-2.ts
  • packages/core/src/task-store/remaining-ops-6.ts
  • packages/core/src/task-store/serialization.ts
  • packages/core/src/task-store/task-creation.ts
  • packages/core/src/task-store/task-row-mappers.ts
  • packages/core/src/task-store/task-update.ts
  • packages/core/src/task-store/workflow-definitions.ts
  • packages/core/src/types.ts
  • packages/core/src/types/board.ts
  • packages/core/src/types/workflow-steps.ts
  • packages/core/src/workflow-capacity.ts
  • packages/core/src/workflow-ir-resolver.ts
  • packages/core/src/workflow-ir.ts
  • packages/core/src/workflow-lifecycle-traits.ts
  • packages/core/src/workflow-step-results.ts
  • packages/core/src/workflow-transition-policy.ts

Comment thread packages/core/src/index.gate.ts
Comment thread packages/core/src/task-store/workflow-definitions.ts Outdated
gsxdsm and others added 2 commits July 19, 2026 11:26
- mirror StaleBinarySchemaError + assertBinaryNotOlderThanDatabase into index.gate.ts (gate-barrel sync rule)
- deleted-workflow and read-error fallbacks now apply built-in prompt overrides like the no-selection branch

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- adoption sweep gets its own try boundary (unrelated integrity-pass throws can no longer skip it)
- resolveWipBudgetColumns: provably-dead defensive fallbacks removed
- durable 'legacy-adoption-drained' marker short-circuits the drain sweep once complete (non-numeric by design — the stale-binary guard ignores unparseable versions; userPaused rows withhold the marker so they stay adoptable after unpause; read failure fails open toward sweeping)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gsxdsm

gsxdsm commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator Author

Re: CodeRabbit review body round 3 (inline posts failed; findings addressed in 9c5e71c):

adoptLegacyTaskRowsOnOpen(store) shares this try block ... adoption never runs this boot cycle

Fixed: the adoption call runs on its own boundary now — it's internally fail-soft, so a bare await is safe, and unrelated integrity-pass throws can no longer skip it.

we are mathematically guaranteed that resolveColumnBudgetKey successfully located targetColumn

Fixed: dropped the provably-dead Array.isArray fallback and [targetColumn] ternary in resolveWipBudgetColumns, with a comment recording why.

paginates through every active task (500/page) on every single store open, forever

Fixed: a durable non-numeric legacy-adoption-drained marker in fusion_schema_migrations short-circuits the sweep once a full drain produces zero mutating plans. Subtleties handled: a plan withheld only by userPaused also withholds the marker (paused rows stay adoptable after unpause); marker read failure fails open toward sweeping; the non-numeric identifier is deliberate — assertBinaryNotOlderThanDatabase ignores unparseable versions by design, documented at both sites. Five new tests cover the marker lifecycle.

🤖 Generated with Claude Code

@gsxdsm
gsxdsm merged commit 05a02e8 into main Jul 19, 2026
7 checks passed
@gsxdsm
gsxdsm deleted the cutover/stack-1-core branch July 19, 2026 18:50
gsxdsm added a commit that referenced this pull request Jul 19, 2026
…on deleted (#2342)

Part **2 of 3** of the IR-driven lifecycle cutover (stacked on #2341;
top is #2335).

**Scope (80 files, packages/engine + cli/pi skill docs +
AGENTS/architecture):** graph-driven column moves via the
column-boundary controller (R1), single-mover scheduler/hold-release
trait cutover (KTD-2/KTD-9), trait re-keyed self-healing + merger with
the R7b confirmed-merge-must-finalize guarantee, graph-exclusive Plan
Review with leased dedup (R4/R5), the executeCore body-lift — zero
legacy re-entry — with fn_review_step + interceptor machinery deleted
and tombstone-ratcheted (R9), builtin workflow runtime fixes (missing
hold handler, unseamed-node column inheritance, no-merge completion
mover), the 6-column benchmark acceptance suite (11 tests) + 12-builtin
lifecycle sweep (94 assertions), and the executor test-harness
modernization. Also retires core's interpreter-cutover scaffolding whose
last consumer (the authoritative driver) dies here.

**Merge order:** #2341 → this → #2335. After #2341 merges, retarget this
to main.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant