diff --git a/.flatbread-proof/issues/iss-writedecision-with-supersedes-leaves-the-superse--by624gyf21ex42sv.md b/.flatbread-proof/issues/iss-writedecision-with-supersedes-leaves-the-superse--by624gyf21ex42sv.md index 9ba4d4a9..2006c8ab 100644 --- a/.flatbread-proof/issues/iss-writedecision-with-supersedes-leaves-the-superse--by624gyf21ex42sv.md +++ b/.flatbread-proof/issues/iss-writedecision-with-supersedes-leaves-the-superse--by624gyf21ex42sv.md @@ -3,10 +3,12 @@ id: iss-writedecision-with-supersedes-leaves-the-superse--by624gyf21ex42sv effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 title: WriteDecision with supersedes leaves the superseded Decision in state accepted kind: defect -status: open +status: resolved created_at: '2026-07-26T05:07:15.240Z' derives_from: - fnd-supersession-transitions-decision-state-on-the-r--2m807tcfjz2jz9gt +resolved_by: + - dec-use-semantic-mutations-and-a-standalone-writer--2d0m3tkqhad4yyhr --- ## Problem diff --git a/packages/proof/src/__tests__/planner.test.ts b/packages/proof/src/__tests__/planner.test.ts index 52fa1d58..57b585f8 100644 --- a/packages/proof/src/__tests__/planner.test.ts +++ b/packages/proof/src/__tests__/planner.test.ts @@ -166,6 +166,41 @@ test('11 WriteFinding with supersedes', (t) => { ); t.deepEqual(w[1].beforeBytes, s.getRawBytes(ids.finding)); }); +test('WriteDecision with supersedes transitions the target state', (t) => { + const target = record(ids.decision, 'decision', { + id: ids.decision, + effort: E, + title: 'Old', + state: 'accepted', + created_at: '2025-01-01T00:00:00.000Z', + }); + const s = snap([target]); + const w = planMutation( + { + type: 'WriteDecision', + id: ids.decision2, + effort: E, + title: 'New', + body: '', + supersedes: [ids.decision], + }, + s, + '/root', + now + ); + const targetFrontmatter = parseDocument( + w[1].afterBytes, + 'decision' + ).frontmatter; + + t.deepEqual( + w.map((write) => write.id), + [ids.decision2, ids.decision] + ); + t.is(targetFrontmatter.state, 'superseded'); + t.deepEqual(targetFrontmatter.superseded_by, [ids.decision2]); + t.deepEqual(w[1].beforeBytes, s.getRawBytes(ids.decision)); +}); test('12 WriteDecision with invalidates', (t) => { const target = record(ids.finding, 'finding', { id: ids.finding, diff --git a/packages/proof/src/__tests__/writer.test.ts b/packages/proof/src/__tests__/writer.test.ts index 05fc0b2c..80c900d6 100644 --- a/packages/proof/src/__tests__/writer.test.ts +++ b/packages/proof/src/__tests__/writer.test.ts @@ -97,6 +97,7 @@ test('WriteDecision with supersedes materializes superseded_by on the target fil }); t.is(result.touched.length, 2); const target = await readFrontmatter(root, `decisions/${older}.md`); + t.is(target.data.state, 'superseded'); t.deepEqual(target.data.superseded_by, [soleId(result)]); const newer = result.artifacts.find((a) => a.operation === 'created')!; t.deepEqual(newer.frontmatter.supersedes, [older]); diff --git a/packages/proof/src/planner.ts b/packages/proof/src/planner.ts index 4b006cc9..8c64e318 100644 --- a/packages/proof/src/planner.ts +++ b/packages/proof/src/planner.ts @@ -359,7 +359,10 @@ export function planMutation( const reverse = edge === 'supersedes' ? 'superseded_by' : 'invalidated_by'; const current = - reverseUpdates.get(target.id)?.frontmatter ?? target.frontmatter; + reverseUpdates.get(target.id)?.frontmatter ?? + (edge === 'supersedes' && target.kind === 'decision' + ? supersedeDecisionLifecycle(snapshot, target.id).nextFrontmatter + : target.frontmatter); reverseUpdates.set(target.id, { target, frontmatter: {