fix(office): stop the stuck-parent wake sweep from failing every tick on Postgres - #3525
fix(office): stop the stuck-parent wake sweep from failing every tick on Postgres#3525nova28 wants to merge 3 commits into
Conversation
ListStuckParents backs ParentWakeReconciler, the level-triggered backstop that re-delivers a task_children_completed wake to a parent whose children have all finished. On PostgreSQL the query could not run at all: it carried three SQLite-only constructs, each rejected at parse time, so every tick logged an error and no parent was ever recovered. - GROUP_CONCAT has no PostgreSQL equivalent; render STRING_AGG there. The ordering is restated inside the aggregate because PostgreSQL does not inherit it from the subquery, and the result has to match the key formatChildSetKey builds on the write side byte for byte. - IS NOT with a column right-hand side is a SQLite extension; IS DISTINCT FROM is standard and means the same thing on both engines. - json_extract is SQLite-only; use the existing dialect.JSONExtract helper, the same remedy already applied to HasPriorTasklessFailedRun. Adds PostgreSQL behaviour tests covering the sweep, the receipt and in-flight-run exclusions, and the equality between the SQL-side and Go-side child-set keys. They skip unless KANDEV_TEST_POSTGRES_DSN is set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ipt tests newPostgresWakeRepo initialised only the task and office repositories, so agent_profiles (owned by the settings store) and workflow_step_participants.created_at (added by the workflow repository's migration, and read by RunnerProjection's third COALESCE arm) never existed. seedPostgresRunner also inserted agent_profiles with an empty agent_id, violating the FK to agents(id) that Postgres enforces. All three tests in wake_receipts_postgres_test.go failed for these harness reasons, not because of the production query.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: QUIET Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: QUIET Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review. 📝 SummarySummary by CodeRabbit
Walkthrough
ChangesWake receipt query compatibility
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to Stuck parent tasks can now be identified and recovered on PostgreSQL while preserving SQLite behavior. The query’s aggregation, receipt handling, and wake-run exclusions are covered, with no current merge-blocking risk identified. Sequence Diagram(s)sequenceDiagram
participant ListStuckParents
participant childSetKeyAggregate
participant PostgreSQL
ListStuckParents->>childSetKeyAggregate: select ordered child-set aggregate
childSetKeyAggregate->>PostgreSQL: render STRING_AGG SQL
ListStuckParents->>PostgreSQL: execute dialect-aware query
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. A rabbit sorts child IDs in line Comment |
|
Claude finished @nova28's task in 3m 14s —— View job Code Review
|
|
| Filename | Overview |
|---|---|
| apps/backend/internal/office/repository/sqlite/wake_receipts.go | Adds correct dialect-specific SQL generation for the parent-wake sweep; its new production comment should be reduced to the invariant. |
| apps/backend/internal/office/repository/sqlite/wake_receipts_postgres_test.go | Adds PostgreSQL-gated integration coverage for query parsing, deterministic child-set keys, receipt matching, and queued-run exclusion. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
Tick[Parent wake reconciliation tick] --> Driver{Repository driver}
Driver -->|pgx| PG[Ordered STRING_AGG and JSONB extraction]
Driver -->|sqlite3| SQLite[GROUP_CONCAT and json_extract]
PG --> Query[ListStuckParents]
SQLite --> Query
Query --> Filter[Exclude matching receipts and in-flight wake runs]
Filter --> Candidates[Return parents requiring recovery]
Reviews (1): Last reviewed commit: "fix(office): boot settings and workflow ..." | Re-trigger Greptile
Review nit: the comment claimed three SQLite-only constructs but the PR description names four (wsp.rowid already fixed in kdlbs#3459). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Tip
PR walkthrough: Open the visual walkthrough
Today: On PostgreSQL, the parent-wake reconciler's
ListStuckParentsquery fails at parse time (syntax error at or near "'b'"), soParentWakeReconciler— the level-triggered backstop that recovers stuck parent tasks — logs an error on every tick and never recovers anything. SQLite is unaffected, which is why CI stayed green.After this: The query parses and runs correctly on both engines; the reconciler backstop works on Postgres exactly as it already does on SQLite.
Who hits this: Anyone running Office on Postgres — every tick of the reconciler, silently, until a parent gets permanently stuck with no automatic recovery.
Scope: Standalone. Two of four related dialect issues in this query already have owners on other PRs (
IS NOT→IS DISTINCT FROMlanded via #3290; thewsp.rowidfallback fixed via #3459). This PR is the remaining two:GROUP_CONCATandjson_extract.Not here: A
sqlguardrule to catch this class of dialect leak (GROUP_CONCAT / json_extract /IS NOT <column>) at CI time before it merges — filed as a follow-up (task01218dab), not this PR, to keep this change a pure bugfix.The parent-wake backstop query used two SQLite-only SQL constructs Postgres rejects outright:
GROUP_CONCAT(...)(no Postgres equivalent) → newchildSetKeyAggregate(driver)picksSTRING_AGG(c.id || ':' || c.state, ',' ORDER BY c.id)on Postgres, and the byte-identical unchangedGROUP_CONCATform on SQLite.json_extract(w.payload, '$.task_id')→dialect.JSONExtract(driver, "w.payload", "task_id"), the existing helper already used for this exact pattern elsewhere in the repo (failure.go,runs_inflight.go,participants.go).A new Postgres-gated test file (
wake_receipts_postgres_test.go,KANDEV_TEST_POSTGRES_DSN-gated perapps/backend/AGENTS.md) exercisesListStuckParentsand theSTRING_AGGaggregate against a real PostgreSQL instance. It runs in CI'spostgres-bootjob (PostgreSQL 16) —internal/office/repository/sqliteis in that job's explicitPOSTGRES_PACKAGESlist.Validation
go build ./...— cleango vet ./internal/office/repository/sqlite/...— cleango test -tags fts5 ./internal/office/repository/sqlite/ -run 'StuckParent|WakeReceipt|ChildSetKey' -count=1 -v— 9 SQLite tests pass; 3 Postgres tests skip locally (noKANDEV_TEST_POSTGRES_DSN), run against real Postgres 16 in CI'spostgres-bootjobgo run ./cmd/sqlguard ./internal— clean (this class of dialect leak isn't yet covered — see follow-up above)gofmt -lon both changed files — cleanmake typecheck test lint— clean, other than pre-existing failures proven identical againstorigin/mainin a scratch worktree (macOS-runner-specificinternal/worktree/agentctl/launcher/etc. TMPDIR path-safety failures, andTestMigrate_PriorityIdempotentunder-tags fts5) — none touch the changed files or packagesmake lint-format— cleanpnpm run i18n:ratchet— no UI source added or modifiedapps/backend/internal/office/repository/sqlite/, zeroapps/web/pathsPossible Improvements
Low risk. One residual, non-blocking: the new
STRING_AGGregression test pins ordering via the derived table's ownORDER BY idas much as viaSTRING_AGG(... ORDER BY c.id)itself, so it's a slightly weaker regression pin than it looks (analysis-level observation, not verified against a live Postgres in this environment).Checklist
apps/web/), I have added or updated Playwright e2e tests inapps/web/e2e/and verified them withmake test-e2e.docs/public/**and updated them or noted why no docs change is needed.Preview Environment
a4af353