Closes the remaining PG-cutover partitioning gaps:
- getWorkflowSettingsProjectId resolves the bound AsyncDataLayer's central-
registry id first. In backend mode the SQLite stub's getProjectIdentity()
throws, so the old fallback ALWAYS keyed workflow_settings /
workflow_prompt_overrides by the rootDir path string — a namespace nothing
else reads, making workflow settings appear reset after cutover.
- Stamping is extracted into core stampMigratedProjectRows (tasks/archived
NULL->id, config ''->id, workflow_settings + workflow_prompt_overrides
rootDir-key->id, all guarded against clobbering per-project rows), shared by
startup-factory Step 5.5 and 'fn db migrate', which now resolves the
registered project by path after the copy and warns when unregistered.
- The task-id allocator and merge_queue are verified safe WITHOUT project
partitioning: task ids are a global PK, the per-prefix sequence scans are
intentionally global (only the per-project config floor can raise them), so
two projects sharing a prefix cannot mint duplicate ids. FNXC comments lock
the invariant; a cross-project PG regression test proves it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>