diff --git a/test/e2e/suite/fullLoop.test.ts b/test/e2e/suite/fullLoop.test.ts index a2ee4d7..5dc8858 100644 --- a/test/e2e/suite/fullLoop.test.ts +++ b/test/e2e/suite/fullLoop.test.ts @@ -140,7 +140,22 @@ suite("full native loop — PUC-7 → PUC-8 → PUC-2 → PUC-1 (§6.8, §7.1 ru assert.ok(claudeSpan, "claude's words are attributed"); assert.ok(humanSpan, "the human tweak is attributed separately (char-honest split)"); - // ---- PUC-2, reject: revert the untouched second proposal in place ---------------- + // ---- PUC-2, reject: revert the second proposal in place -------------------------- + // #70 (INV-5): the reject leg now ALSO takes an interior tweak first — the + // original deliberately rejected only an un-tweaked proposal because the + // pre-fix revert silently skipped an orphaned anchor. The tweak orphans the + // exact anchor; the revert must restore ORIG_REJECT via the tracked span. + const rejAt = doc.getText().indexOf(REJECT_REPLACEMENT); + assert.ok(rejAt >= 0, "reject proposal's applied text present"); + const rejTweak = new vscode.WorkspaceEdit(); + rejTweak.replace(doc.uri, new vscode.Range(doc.positionAt(rejAt + 2), doc.positionAt(rejAt + 2)), "x"); + assert.ok(await vscode.workspace.applyEdit(rejTweak), "human tweak inside the reject proposal's range"); + await settle(); + assert.strictEqual( + api.proposalController.listProposals(doc).find((v) => v.id === rejectId)!.anchorStart, + null, + "tweak orphans the reject proposal's exact anchor (INV-11)", + ); assert.ok(await api.proposalController.revertInPlace(docKey, rejectId), "reject reverts in place"); await settle(); assert.strictEqual(