mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(dream): deterministic last-writer attribution for colliding slugs
collectChildPutPageSlugs paired each slug to a jobId first-seen over an unordered result set. When two children collide on a final slug, the pages row holds the LAST put_page write, so the provenance stamp (transcript_id/transcript_source/date) could attribute an arbitrary other transcript. ORDER BY id + last-writer-wins aligns the stamp with the surviving content; pinned by a collision test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
093d693502
commit
bcdb435d73
@@ -1139,7 +1139,8 @@ async function collectChildPutPageSlugs(
|
||||
FROM subagent_tool_executions
|
||||
WHERE job_id = ANY($1::int[])
|
||||
AND tool_name = 'brain_put_page'
|
||||
AND status = 'complete'`,
|
||||
AND status = 'complete'
|
||||
ORDER BY id`,
|
||||
[childIds],
|
||||
);
|
||||
const rewritten = new Map<string, number>();
|
||||
@@ -1149,7 +1150,10 @@ async function collectChildPutPageSlugs(
|
||||
const finalSlug = meta && meta.chunkTotal > 1
|
||||
? rewriteChunkedSlug(r.slug, meta.hash6, meta.idx)
|
||||
: r.slug;
|
||||
if (!rewritten.has(finalSlug)) rewritten.set(finalSlug, r.job_id);
|
||||
// Last writer wins, in execution-row order (ORDER BY id): if two children
|
||||
// collide on a final slug, the pages row holds the LAST put_page write, so
|
||||
// the stamp must attribute that child's transcript — not an arbitrary one.
|
||||
rewritten.set(finalSlug, r.job_id);
|
||||
}
|
||||
return [...rewritten.entries()]
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
|
||||
@@ -174,6 +174,25 @@ describe('#2285: orchestrator-owned deterministic transcript frontmatter', () =>
|
||||
}
|
||||
});
|
||||
|
||||
test('slug collision across children attributes the LAST writer (matches surviving putPage)', async () => {
|
||||
const db = (engine as any).db;
|
||||
// Jobs 1001 then 1002 write the same slug; the pages row would hold
|
||||
// 1002's content (last put_page wins), so the ref must carry jobId 1002.
|
||||
await db.query(
|
||||
`INSERT INTO subagent_tool_executions (job_id, message_idx, tool_use_id, tool_name, status, input)
|
||||
VALUES (1001, 9, 'tool_dup_a', 'brain_put_page', 'complete', $1::jsonb)`,
|
||||
[JSON.stringify({ slug: 'wiki/agents/test/collision', body: 'first' })],
|
||||
);
|
||||
await db.query(
|
||||
`INSERT INTO subagent_tool_executions (job_id, message_idx, tool_use_id, tool_name, status, input)
|
||||
VALUES (1002, 9, 'tool_dup_b', 'brain_put_page', 'complete', $1::jsonb)`,
|
||||
[JSON.stringify({ slug: 'wiki/agents/test/collision', body: 'second' })],
|
||||
);
|
||||
const refs = await collectChildPutPageSlugs(engine as any, [1001, 1002], new Map());
|
||||
const hit = refs.find((r: { slug: string }) => r.slug === 'wiki/agents/test/collision');
|
||||
expect(hit?.jobId).toBe(1002);
|
||||
});
|
||||
|
||||
test('stampDreamProvenance merges the transcript metadata into DB frontmatter', async () => {
|
||||
const slug = 'wiki/originals/ideas/2026-07-17-transcript-meta-abc123';
|
||||
await engine.putPage(slug, {
|
||||
|
||||
Reference in New Issue
Block a user