Item 1 — sources.ts triple INSERT/UPDATE postgres-js double-encoding (root cause):
Sites: src/commands/sources.ts:211 (runAdd), :471 (runUpdate), :407 (runFederate)
Pattern: `JSON.stringify(config)` + `$N::jsonb` cast via `engine.executeRaw`
→ postgres-js's `unsafe()` API auto-encodes string params on `::jsonb` cast,
re-stringifies the JSON content as a JSON STRING literal, lands in DB as
jsonb_typeof = 'string' (not 'object'). Subsequent `jsonb_set()` migrations
throw SQLSTATE 22023 'cannot set path in scalar'.
Empirical verification (D-LXC fixture 189, 2026-05-07):
Variant 1: `JSON.stringify(o)` + `$N::jsonb` → string ✗ (current)
Variant 2: object `o` + `$N::jsonb` → object ✓
Variant 3: `JSON.stringify(o)` + no cast → string ✗
Variant 4: `JSON.stringify(o)` + `($N::text)::jsonb` → object ✓ (this fix)
Fix: `($N::text)::jsonb` double cast forces postgres-js to send param
verbatim as TEXT (not jsonb-typed), then SQL re-parses to object at column
boundary. Variant 4 over Variant 2 because it's defensive across postgres-js
versions and the `unsafe()` API contract.
Pairs with v26 step 0 healing (fork commit 71aaf22) which recovers
pre-existing string-encoded prod data. After this commit, NEW sources
written by `gbrain sources add` / `sources update` / `sources federate`
land as objects directly, no heal needed for newly created rows.
Test: e2e jsonb-roundtrip extended with sources INSERT/UPDATE coverage +
source-grep tripwire that flags any future regressions.
Item 2 — sync.ts up_to_date path fails to advance last_sync_at:
Site: src/commands/sync.ts:211-221 performSync `lastCommit === headCommit`
branch returns immediately without updating sources.last_sync_at. Quiet
sources (read-mostly repos) keep stale last_sync_at indefinitely; drift
monitor (gbrain-projects-drift.sh) flags them stale even though the sync
cron is firing every tick.
Fix: advance last_sync_at on up_to_date branch via direct UPDATE (only
last_sync_at, not last_commit since the commit anchor is genuinely
unchanged). Preserves drift contract: "is the sync cron alive?" not
"did the remote add commits?".
Surfaced 2026-05-07 PW 1 part 2 prod deploy on LXC 107 — first drift
tick post-deploy reported stock-dashboard 'stale 6197min ago' 30 seconds
after a successful sync tick.
Test: tests/sync-up-to-date-stamping.test.ts (3 cases) — quiet repo
bumps last_sync_at, last_commit anchor stable, legacy non-sourceId path
no-throws + records sync.last_run.
Both bugs were pre-existing (not introduced by PW 1 part 2 fork patches).
Both surfaced during prod deploy because v26 was the first migration to
hit jsonb_set on long-existing string-encoded configs, and PW 1 part 2's
new drift monitor read sources.last_sync_at directly (vs sync.sh's own
audit log in the prior implementation).
88/88 tests pass across allowlist / migration-v26 / sync-walk-dispatch /
sync-up-to-date-stamping / manifest-routing / manifest-edge-cases /
source-resolver / brain-allowlist / ingest-log-source-id.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>