From 92ff4dd4acfcfe72ac98097a6b37d94cb33f5485 Mon Sep 17 00:00:00 2001 From: BenStullsBets Date: Fri, 26 Jun 2026 06:17:38 -0700 Subject: [PATCH] feat(proposalModel): setProposalApplied re-anchors + stores original (#64) Co-Authored-By: Claude Sonnet 4.6 --- src/proposalModel.ts | 19 +++++++++++++++++++ test/proposalModel.test.ts | 17 ++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/proposalModel.ts b/src/proposalModel.ts index 8aa57cf..4aefbee 100644 --- a/src/proposalModel.ts +++ b/src/proposalModel.ts @@ -37,6 +37,25 @@ export function removeProposal(artifact: Artifact, proposalId: string): boolean return artifact.proposals.length < before; } +/** + * F12/#64 (INV-48): record a proposal as optimistically applied — store the + * pre-apply `original` (for revert + the struck ``) and re-point its anchor + * fingerprint to the now-in-buffer applied text so `resolve()` finds it. Idempotent + * shape: a second call simply overwrites with the same values. + */ +export function setProposalApplied( + artifact: Artifact, + proposalId: string, + appliedFp: Fingerprint, + original: string, +): boolean { + const p = artifact.proposals.find((x) => x.id === proposalId); + if (!p) return false; + p.original = original; + artifact.anchors[p.anchorId] = { fingerprint: appliedFp }; + return true; +} + /** Markdown comment body: instruction header + fenced whole-range diff. */ export function proposalBody(targetText: string, p: Proposal): string { const header = p.instruction ? `**Claude proposes** — _${p.instruction}_` : "**Claude proposes**"; diff --git a/test/proposalModel.test.ts b/test/proposalModel.test.ts index 9fce315..1075658 100644 --- a/test/proposalModel.test.ts +++ b/test/proposalModel.test.ts @@ -9,7 +9,7 @@ import { type Proposal, } from "../src/model"; import { CoauthorStore } from "../src/store"; -import { addProposal, proposalBody, removeProposal } from "../src/proposalModel"; +import { addProposal, proposalBody, removeProposal, setProposalApplied } from "../src/proposalModel"; const agent = { kind: "agent" as const, @@ -104,4 +104,19 @@ describe("proposalModel helpers (spec §6.4)", () => { expect(body).toContain("- old line two"); expect(body).toContain("+ new only line"); }); + + it("setProposalApplied stores original and re-anchors the fingerprint to the applied text", () => { + const a = emptyArtifact("docs/x.md"); + const { proposalId, anchorId } = addProposal( + a, + { text: "old", before: "", after: "", lineHint: 0 }, + "new", + { kind: "agent", id: "claude", agent: { sdk: "x", model: "m", sessionId: "s" } }, + { granularity: "block" }, + ); + setProposalApplied(a, proposalId, { text: "new", before: "", after: "", lineHint: 0 }, "old"); + const p = a.proposals.find((x) => x.id === proposalId)!; + expect(p.original).toBe("old"); + expect(a.anchors[anchorId].fingerprint.text).toBe("new"); + }); });