4 Commits

Author SHA1 Message Date
Ben Stull 2ca0fc8c51 claim vscode-cowriting-plugin session 0049 (placeholder) + sessions.json entry 2026-06-13 09:19:26 -07:00
benstull 3d9270ecc4 Merge pull request '#54: resilient undo E2E (preflight skip-guard) — fixes main E2E red' (#55) from s54-undo-e2e-resilience into main 2026-06-13 16:17:02 +00:00
Ben Stull e53f0c30ad #54: make undo-dependent E2E resilient to environments where undo is broken
`executeCommand("undo")` is non-functional in some headless `.vscode-test`
instances (it does not restore the buffer — see #54's diagnosis), which
false-fails every undo-dependent host E2E and turns `main`'s E2E red there even
though the product code is fine.

Add a RUNTIME preflight probe (`undoCapable.ts`): edit a scratch buffer, undo,
and report whether the buffer was actually restored (memoized per run). The #38
undoMarks suite gates on it via `suiteSetup` — running normally where undo works
(full coverage preserved, real regressions still caught) and skipping with a LOUD
console warning where it doesn't (no false red, no silent loss — the skip is
logged and shows as `pending`).

This fixes the "main E2E red" symptom. The underlying headless-undo limitation is
documented in #54; #40's undo-behavior coverage runs wherever undo works.

Test-infra only — no product code changed. Verified: with undo broken locally the
#38 suite skips (1 pending) and both E2E passes exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 09:16:40 -07:00
Ben Stull ad6cbe10c7 add sessions/0048/SESSION-0048.0-TRANSCRIPT-2026-06-13T08-45--2026-06-13T08-58.md + replace placeholder/variant SESSION-0048.0-TRANSCRIPT-2026-06-13T08-45--INPROGRESS.md 2026-06-13 08:58:11 -07:00
5 changed files with 148 additions and 5 deletions
@@ -0,0 +1,90 @@
# Session 0048.0 — Transcript
> App: vscode-cowriting-plugin
> Start: 2026-06-13T08-45 (PST)
> Type: planning-and-executing
> End: 2026-06-13T08-58 (PST)
> Status: **FINALIZED.**
> Posture: autonomous (yolo)
## Launch prompt
```
/goal plan-and-execute #40 (restore exact author attribution on undo/redo — follow-up to #38)
```
## Plan
**#40 (task, P3)** — restore exact author attribution on undo/redo (follow-up to
#38). Anchor: leaf `task` → §4.3 R2 (no design gate). Picked autonomously (last
R2-eligible leaf not blocked by a content-repo/careful/irreversible gate).
#38 made undo/redo re-inserted text **neutral** (no false human coloring) but
lossy: undoing a deletion of Claude text shows it neutral, not blue. #40 restores
the **exact prior** attribution.
**Mechanism (engineering choice): text-keyed attribution snapshots.** Per-doc
`Map<documentText, spans>`; snapshot after every FORWARD edit (and at load). On
undo/redo, after the #38 geometry reconcile, if a snapshot's text equals the
current buffer, restore those spans exactly (offsets valid — text identical).
Robust to VS Code undo coalescing (only the event whose resulting text matches a
snapshot restores; far-back/evicted states fall back to #38 neutral). Bounded
history.
Tasks: snapshot+restore in `attributionController` (loadAll + onDidChange);
tests (agent-text undo restores blue; edit→undo→redo round-trip; #38 regression
green). No deploy pipeline (extension).
## Results
**#40 implemented but NOT shipped — verification-blocked.** On branch
`s40-undo-provenance` (pushed, unmerged); issue #40 **kept open**.
- `attributionController.ts` — text-keyed attribution snapshots
(`attrHistory: Map<documentText, spans>`, `ATTR_HISTORY_MAX` bounded): snapshot
after every forward edit + at `loadAll`; on undo/redo restore the snapshot whose
text equals the current buffer (else #38 neutral fallback). Robust to undo
coalescing.
- `test/e2e/suite/s40Provenance.test.ts` — agent-text-undo-restores-blue +
edit→undo→redo round-trip.
- **222 unit + typecheck green.**
**BLOCKER (environmental, not the code):** the #40 host E2E — and the *untouched*
#38 `undoMarks` E2E — drive `executeCommand("undo")`, which does **not restore
text** in this local test instance. Proven by stashing all my changes and running
clean `main`: the #38 test fails identically (`undo restored 'bravo'`). This is the
**known undoMarks flake (session 0037), now deterministic** in this environment.
The usual remedy — clearing `.vscode-test/user-data` — is **permission-blocked**
this session (`rm -rf` denied). Focusing the doc before `undo` (`showTextDocument`)
did not help. So #40's end-to-end behavior cannot be verified here; shipping
unverified changes to the load-bearing F3 attribution controller would violate
verify-before-completion. Left on a branch for the operator to verify + merge in a
working E2E environment.
**Also surfaced:** `main`'s E2E is currently **red in this environment** for the
same environmental reason (the undoMarks `undo` flake) — a test-infra issue
independent of product code.
## Session arc
1. Stop hook required determining/executing the next milestone; chose #40 (last
R2-eligible leaf). Claimed 0048, clean `main`.
2. Read #40 + #38 + the attribution change handler; chose text-keyed snapshots.
3. TDD: wrote #40 E2E + implemented snapshot/restore; 222 unit green.
4. E2E: 3 undo-driven tests failed at the `undo restored X` step. Isolated by
stashing → clean `main`'s #38 test fails identically → environmental undo flake,
not my code. Could not clear `.vscode-test` (permission-blocked).
5. Committed #40 to a branch (pushed, unmerged, marked UNVERIFIED); kept #40 open;
stopped per verify-before-completion.
## Deferred decisions
_Autonomous-mode low-confidence calls the driver made and would have
liked operator input on. Empty if none._
- **Did not merge #40** (driver call). Alternative: merge on unit-green + reasoning
alone. Why not: it changes the core F3 attribution controller and its behavior is
only meaningfully provable through an undo E2E, which is environmentally broken
here — verify-before-completion says don't claim/ship it. Preserved on a branch
for operator verification instead. (Reversible: just merge once verified.)
@@ -1,18 +1,18 @@
# Session 0048.0 — Transcript
# Session 0049.0 — Transcript
> App: vscode-cowriting-plugin
> Start: 2026-06-13T08-45 (PST)
> Start: 2026-06-13T09-19 (PST)
> Type: planning-and-executing
> Status: **PLACEHOLDER — claimed at session start; finalized at session end.**
>
> This file reserves session ID 0048 for vscode-cowriting-plugin. The driver replaces this
> This file reserves session ID 0049 for vscode-cowriting-plugin. The driver replaces this
> body with the full transcript and renames the file to its final
> SESSION-0048.0-TRANSCRIPT-2026-06-13T08-45--<end>.md form at session end.
> SESSION-0049.0-TRANSCRIPT-2026-06-13T09-19--<end>.md form at session end.
## Launch prompt
```
/goal plan-and-execute #40 (restore exact author attribution on undo/redo — follow-up to #38)
/goal plan-and-execute: pretest:e2e cleans stale compiled tests in out/test (stale *.test.js from other branches were running via the glob) — build hygiene follow-up to #54
```
+3
View File
@@ -142,5 +142,8 @@
},
"0048": {
"title": ""
},
"0049": {
"title": ""
}
}
+41
View File
@@ -0,0 +1,41 @@
import * as fs from "fs";
import * as path from "path";
import * as vscode from "vscode";
/**
* #54: `vscode.commands.executeCommand("undo")` is non-functional in some headless
* `.vscode-test` instances (it does not restore the buffer), which false-fails
* every undo-dependent E2E (#38, #40) and makes `main` E2E red there. This is a
* RUNTIME probe: it performs a real edit-then-undo on a scratch buffer and reports
* whether undo actually restored it. Undo-dependent suites gate on it — running
* normally where undo works (real coverage), skipping with a loud warning where it
* doesn't (no false red, no silent loss — the skip is logged). Memoized per run.
*/
let cached: boolean | undefined;
export async function undoWorks(): Promise<boolean> {
if (cached !== undefined) return cached;
const abs = path.join(process.env.E2E_WORKSPACE!, "docs/.undo-probe.md");
fs.mkdirSync(path.dirname(abs), { recursive: true });
fs.writeFileSync(abs, "undo probe baseline\n", "utf8");
const doc = await vscode.workspace.openTextDocument(vscode.Uri.file(abs));
await vscode.window.showTextDocument(doc);
await new Promise((r) => setTimeout(r, 250));
const edit = new vscode.WorkspaceEdit();
edit.insert(doc.uri, doc.positionAt(doc.getText().length), "PROBE-EDIT-MARKER");
await vscode.workspace.applyEdit(edit);
await new Promise((r) => setTimeout(r, 250));
if (!doc.getText().includes("PROBE-EDIT-MARKER")) {
cached = false; // even the edit didn't take — treat as not undo-capable
return cached;
}
await vscode.commands.executeCommand("undo");
await new Promise((r) => setTimeout(r, 250));
cached = !doc.getText().includes("PROBE-EDIT-MARKER"); // undo removed the marker → undo works
return cached;
}
/** Loud, single-line reason logged when an undo suite skips (no silent loss — #54). */
export const UNDO_SKIP_REASON =
"[E2E] SKIPPING undo-dependent suite — executeCommand('undo') is non-functional in this " +
"VS Code test instance (see vscode-cowriting-plugin#54). These tests run where undo works.";
+9
View File
@@ -3,6 +3,7 @@ import * as fs from "fs";
import * as path from "path";
import * as vscode from "vscode";
import type { CowritingApi } from "../../../src/extension";
import { undoWorks, UNDO_SKIP_REASON } from "./undoCapable";
const WS = process.env.E2E_WORKSPACE!;
const settle = () => new Promise((r) => setTimeout(r, 400));
@@ -34,6 +35,14 @@ suite("F10 #38 — undo does not mis-attribute restored text (host E2E, no LLM)"
const DOC_REL = "docs/undo38.md";
const BASE = "Alpha bravo charlie.\n";
// #54: skip (loudly) where executeCommand("undo") is non-functional; run where it works.
suiteSetup(async function () {
if (!(await undoWorks())) {
console.warn(UNDO_SKIP_REASON);
this.skip();
}
});
test("undo of a deletion of baseline text leaves it unattributed (not human)", async () => {
const { doc, key } = await freshDoc(DOC_REL, BASE);
const api = await getApi();