Skip to content

Fix double-encoded jsonb breaking dream cycle slug lookup#745

Open
joelwp wants to merge 1 commit intogarrytan:masterfrom
joelwp:fix/double-encoded-tool-input-slug-lookup
Open

Fix double-encoded jsonb breaking dream cycle slug lookup#745
joelwp wants to merge 1 commit intogarrytan:masterfrom
joelwp:fix/double-encoded-tool-input-slug-lookup

Conversation

@joelwp
Copy link
Copy Markdown

@joelwp joelwp commented May 8, 2026

Summary

  • Bug: persistToolExecPending/Failed/Complete in subagent.ts call JSON.stringify(input) before passing to a $N::jsonb parameter. When input is already an object, this produces a JSON string which ::jsonb stores as a jsonb scalar — not a jsonb object. Downstream queries like input->>'slug' then return NULL.
  • Symptom: Dream cycle synthesize phase always reports pages_written: 0 even when subagents successfully write pages via brain_put_page. The summary page shows "Pages written: 0" despite pages existing in the DB.
  • Same bug in patterns.ts slug collection query.

Fix

  1. Root cause (subagent.ts): Skip JSON.stringify when input/output is already a string, preventing future double-encoding.
  2. Query fix (synthesize.ts, patterns.ts): Use COALESCE(input->>'slug', (input #>> '{}')::jsonb->>'slug') to handle both old double-encoded rows and new properly-encoded rows.

Files changed

  • src/core/minions/handlers/subagent.ts — persist functions
  • src/core/cycle/synthesize.tscollectChildPutPageSlugs
  • src/core/cycle/patterns.ts — same query pattern

Test plan

  • Run gbrain dream --date <date> with existing double-encoded rows — summary should now show correct page count
  • Run a new dream cycle — verify subagent_tool_executions.input is stored as jsonb object (not scalar string)
  • Verify input->>'slug' returns the slug for both old and new rows

🤖 Generated with Claude Code


View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

…okup

persistToolExecPending/Failed/Complete called JSON.stringify(input) before
passing to a $N::jsonb parameter. When input is already an object, this
produces a JSON string which ::jsonb stores as a jsonb scalar -- not a
jsonb object. Downstream queries like input->>slug then return NULL
because the operator does not traverse scalar strings.

Root cause fix: skip JSON.stringify when input is already a string.

Query fix: use COALESCE with (input #>> '{}')::jsonb->>slug fallback
to handle both old double-encoded rows and new properly-encoded rows.

Affects: dream cycle synthesize phase (pages_written always 0) and
patterns phase (same slug collection query).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
garrytan added a commit that referenced this pull request May 9, 2026
Codex-mandated test gate (C6 from /codex review of v0.30.3 plan).

Pins behavior of collectChildPutPageSlugs() under both jsonb shapes:
- jsonb_typeof='object' (post-#745, normal write path)
- jsonb_typeof='string' (pre-#745 double-encoded, the bug shape)

Without this guard, a future regression of #745 would silently drop slugs:
child jobs finish, queue looks healthy, orchestrator writes nothing.
Worst on-call shape — silent failure with no alerting surface.

Adds an `__testing` namespace to src/core/cycle/synthesize.ts re-exporting
collectChildPutPageSlugs at unit-test granularity. Not part of the runtime
contract; matches the v0_29_1.ts `__testing` precedent for engine-internal
helpers.
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