Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1064bfd

Browse files
author
Paul Bakaus
committed
Fix live recovery review issues
1 parent 5baac4b commit 1064bfd

58 files changed

Lines changed: 369 additions & 127 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/impeccable/reference/live.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Execute in order. No step skipped, no step reordered.
1212
2. Navigate to the URL that serves `pageFile` (infer from `package.json`, docs, terminal output, or an open tab). If you can't infer it confidently, tell the user once to open their dev/preview URL. Never use `serverPort` as that URL; it's the helper, not the app.
1313
3. Poll loop with the default long timeout (600000 ms). After every event or `--reply`, run `live-poll.mjs` again immediately. Never pass a short `--timeout=`.
1414
4. On `generate`: read screenshot if present; load the action's reference; plan three distinct directions; write all variants in one edit; `--reply done`; poll again.
15-
5. On `accept` / `discard`: the poll script runs `live-accept.mjs`, acknowledges durable completion (`complete` / `discarded`), and prints `_completionAck`; finish any carbonize cleanup before polling again.
15+
5. On `accept` / `discard`: the poll script runs `live-accept.mjs`, acknowledges the delivered event, and prints `_completionAck`. Plain accepts/discards are terminal immediately; carbonize accepts remain recoverable until you finish cleanup, run `live-complete.mjs --id EVENT_ID`, and only then poll again.
1616
6. If interrupted, run `live-status.mjs` or `live-resume.mjs` before guessing. The durable journal replays unacknowledged work after helper restart.
1717
7. On `exit`: run the cleanup at the bottom.
1818

@@ -65,7 +65,7 @@ node .agents/skills/impeccable/scripts/live-complete.mjs --id SESSION_ID
6565

6666
- `live-status.mjs` prints connected helper state, active durable sessions, and queued pending events. It works even when the helper is down by reading the journal directly.
6767
- `live-resume.mjs` prints the active snapshot, pending event, checkpoint phase, visible variant, parameter values, and the next safe agent action.
68-
- `live-complete.mjs` is the canonical manual final acknowledgement. Use it only after you have verified cleanup is complete and no further poll acknowledgement will happen automatically.
68+
- `live-complete.mjs` is the canonical manual final acknowledgement. Use it after carbonize/manual cleanup is verified and no further poll acknowledgement will happen automatically.
6969

7070
Server restart rule: start `live-server.mjs` again, then poll. Startup requeues unacknowledged pending events from the journal, so do not ask the user to click Go again unless `live-resume.mjs` says no active session exists.
7171

@@ -396,11 +396,11 @@ Remove the wrapper you inserted in Step 2. Nothing else to do.
396396

397397
## Handle `accept`
398398

399-
Event: `{id, variantId, _acceptResult, _completionAck}`. The poll script already ran `live-accept.mjs` to handle the file operation deterministically, then acknowledged durable completion to the helper. The browser DOM is already updated.
399+
Event: `{id, variantId, _acceptResult, _completionAck}`. The poll script already ran `live-accept.mjs` to handle the file operation deterministically, then acknowledged event delivery to the helper. The browser DOM is already updated.
400400

401401
- `_completionAck.ok !== true`: do not poll yet. Run `live-status.mjs` / `live-resume.mjs`, complete the cleanup manually if needed, then run `live-complete.mjs --id EVENT_ID`.
402402
- `_acceptResult.handled: true` and `carbonize: false`: nothing to do. Poll again.
403-
- `_acceptResult.handled: true` and `carbonize: true`: **post-accept cleanup is required before the next poll.** See the "Required after accept (carbonize)" section below. The `event._acceptResult.todo` field and a stderr banner both list the steps explicitly; neither is decorative.
403+
- `_acceptResult.handled: true` and `carbonize: true`: **post-accept cleanup is required before the next poll.** See the "Required after accept (carbonize)" section below. The `event._acceptResult.todo` field, `_completionAck.requiresComplete`, and a stderr banner all point at this required follow-up; none are decorative. After cleanup, run `live-complete.mjs --id EVENT_ID`, then poll again.
404404
- `_acceptResult.handled: false, mode: "fallback"`: the session lived in a generated file and the script refused to persist there. You've already written the accepted variant into true source during Handle fallback Step 3; just clean up the temporary wrapper in the served file if any, and poll again.
405405
- `_acceptResult.handled: false` without `mode`: manual cleanup: read file, find markers, edit.
406406

@@ -416,7 +416,7 @@ Do these five steps in the current thread, synchronously, before the next poll.
416416
4. **Unwrap the accepted content.** Delete the `<div data-impeccable-variant="N" style="display: contents">` that wraps it. Drop `data-impeccable-params` and any `data-p-*` attributes from it; those are live-mode plumbing, not source.
417417
5. **Delete the inline `<style>` block, the `<!-- impeccable-param-values -->` comment if present, and both `<!-- impeccable-carbonize-start/end -->` markers.** Also drop any `@scope` rules for variants other than the accepted one; those are dead code now.
418418

419-
Then poll again.
419+
After the file is clean, run `live-complete.mjs --id SESSION_ID`, verify it reports `phase: "completed"`, then poll again.
420420

421421
A background agent may be used for the rewrite, but the current thread is responsible for verifying the five steps are complete before issuing the next poll. In practice, inline is usually faster and less error-prone.
422422

.agents/skills/impeccable/scripts/live-completion.mjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,14 @@ export function completionTypeForAcceptResult(eventType, acceptResult) {
55
if (acceptResult?.mode === 'error') return 'error';
66
return 'agent_done';
77
}
8+
9+
export function completionAckForAcceptResult(eventId, completionType, acceptResult) {
10+
const ack = { ok: true, type: completionType };
11+
if (acceptResult?.handled === true && acceptResult?.carbonize === true) {
12+
ack.final = false;
13+
ack.requiresComplete = true;
14+
ack.nextCommand = `live-complete.mjs --id ${eventId}`;
15+
ack.message = 'Carbonize cleanup must be verified, then the session must be completed explicitly before polling again.';
16+
}
17+
return ack;
18+
}

.agents/skills/impeccable/scripts/live-poll.mjs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import { execFileSync } from 'node:child_process';
1212
import path from 'node:path';
1313
import { fileURLToPath } from 'node:url';
14-
import { completionTypeForAcceptResult } from './live-completion.mjs';
14+
import { completionAckForAcceptResult, completionTypeForAcceptResult } from './live-completion.mjs';
1515
import { readLiveServerInfo } from './impeccable-paths.mjs';
1616

1717
// Node's built-in fetch (undici under the hood) enforces a 300s headers
@@ -169,14 +169,16 @@ Options:
169169
} catch (err) {
170170
event._completionAck = { ok: false, error: err.message };
171171
}
172-
if (!event._completionAck) event._completionAck = { ok: true, type: completionType };
172+
if (!event._completionAck) {
173+
event._completionAck = completionAckForAcceptResult(event.id, completionType, event._acceptResult);
174+
}
173175
}
174176

175177
// Second signal path: stderr banner in case the agent parses stdout
176178
// JSON but skips nested fields. One line is enough — the full checklist
177179
// is in reference/live.md.
178180
if (event._acceptResult?.carbonize === true) {
179-
process.stderr.write('\n⚠ Carbonize cleanup REQUIRED before next poll. See reference/live.md "Required after accept".\n\n');
181+
process.stderr.write('\n⚠ Carbonize cleanup REQUIRED before next poll. After cleanup, run live-complete.mjs --id ' + event.id + '. See reference/live.md "Required after accept".\n\n');
180182
}
181183

182184
// Print the event as JSON — the agent reads this from stdout

.agents/skills/impeccable/scripts/live-session-store.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ function rebuildSnapshotFromJournal(journalPath, id) {
137137
const entry = JSON.parse(line);
138138
if (!entry || typeof entry !== 'object') throw new Error('entry is not object');
139139
if (Number.isInteger(entry.seq)) nextSeq = Math.max(nextSeq, entry.seq + 1);
140-
snapshot = applyEvent(snapshot, entry, diagnostics);
140+
snapshot = applyEvent(snapshot, entry);
141141
} catch (err) {
142142
diagnostics.push({
143143
error: 'journal_parse_failed',

.claude/skills/impeccable/reference/live.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Execute in order. No step skipped, no step reordered.
1212
2. Navigate to the URL that serves `pageFile` (infer from `package.json`, docs, terminal output, or an open tab). If you can't infer it confidently, tell the user once to open their dev/preview URL. Never use `serverPort` as that URL; it's the helper, not the app.
1313
3. Poll loop with the default long timeout (600000 ms). After every event or `--reply`, run `live-poll.mjs` again immediately. Never pass a short `--timeout=`.
1414
4. On `generate`: read screenshot if present; load the action's reference; plan three distinct directions; write all variants in one edit; `--reply done`; poll again.
15-
5. On `accept` / `discard`: the poll script runs `live-accept.mjs`, acknowledges durable completion (`complete` / `discarded`), and prints `_completionAck`; finish any carbonize cleanup before polling again.
15+
5. On `accept` / `discard`: the poll script runs `live-accept.mjs`, acknowledges the delivered event, and prints `_completionAck`. Plain accepts/discards are terminal immediately; carbonize accepts remain recoverable until you finish cleanup, run `live-complete.mjs --id EVENT_ID`, and only then poll again.
1616
6. If interrupted, run `live-status.mjs` or `live-resume.mjs` before guessing. The durable journal replays unacknowledged work after helper restart.
1717
7. On `exit`: run the cleanup at the bottom.
1818

@@ -65,7 +65,7 @@ node .claude/skills/impeccable/scripts/live-complete.mjs --id SESSION_ID
6565

6666
- `live-status.mjs` prints connected helper state, active durable sessions, and queued pending events. It works even when the helper is down by reading the journal directly.
6767
- `live-resume.mjs` prints the active snapshot, pending event, checkpoint phase, visible variant, parameter values, and the next safe agent action.
68-
- `live-complete.mjs` is the canonical manual final acknowledgement. Use it only after you have verified cleanup is complete and no further poll acknowledgement will happen automatically.
68+
- `live-complete.mjs` is the canonical manual final acknowledgement. Use it after carbonize/manual cleanup is verified and no further poll acknowledgement will happen automatically.
6969

7070
Server restart rule: start `live-server.mjs` again, then poll. Startup requeues unacknowledged pending events from the journal, so do not ask the user to click Go again unless `live-resume.mjs` says no active session exists.
7171

@@ -396,11 +396,11 @@ Remove the wrapper you inserted in Step 2. Nothing else to do.
396396

397397
## Handle `accept`
398398

399-
Event: `{id, variantId, _acceptResult, _completionAck}`. The poll script already ran `live-accept.mjs` to handle the file operation deterministically, then acknowledged durable completion to the helper. The browser DOM is already updated.
399+
Event: `{id, variantId, _acceptResult, _completionAck}`. The poll script already ran `live-accept.mjs` to handle the file operation deterministically, then acknowledged event delivery to the helper. The browser DOM is already updated.
400400

401401
- `_completionAck.ok !== true`: do not poll yet. Run `live-status.mjs` / `live-resume.mjs`, complete the cleanup manually if needed, then run `live-complete.mjs --id EVENT_ID`.
402402
- `_acceptResult.handled: true` and `carbonize: false`: nothing to do. Poll again.
403-
- `_acceptResult.handled: true` and `carbonize: true`: **post-accept cleanup is required before the next poll.** See the "Required after accept (carbonize)" section below. The `event._acceptResult.todo` field and a stderr banner both list the steps explicitly; neither is decorative.
403+
- `_acceptResult.handled: true` and `carbonize: true`: **post-accept cleanup is required before the next poll.** See the "Required after accept (carbonize)" section below. The `event._acceptResult.todo` field, `_completionAck.requiresComplete`, and a stderr banner all point at this required follow-up; none are decorative. After cleanup, run `live-complete.mjs --id EVENT_ID`, then poll again.
404404
- `_acceptResult.handled: false, mode: "fallback"`: the session lived in a generated file and the script refused to persist there. You've already written the accepted variant into true source during Handle fallback Step 3; just clean up the temporary wrapper in the served file if any, and poll again.
405405
- `_acceptResult.handled: false` without `mode`: manual cleanup: read file, find markers, edit.
406406

@@ -416,7 +416,7 @@ Do these five steps in the current thread, synchronously, before the next poll.
416416
4. **Unwrap the accepted content.** Delete the `<div data-impeccable-variant="N" style="display: contents">` that wraps it. Drop `data-impeccable-params` and any `data-p-*` attributes from it; those are live-mode plumbing, not source.
417417
5. **Delete the inline `<style>` block, the `<!-- impeccable-param-values -->` comment if present, and both `<!-- impeccable-carbonize-start/end -->` markers.** Also drop any `@scope` rules for variants other than the accepted one; those are dead code now.
418418

419-
Then poll again.
419+
After the file is clean, run `live-complete.mjs --id SESSION_ID`, verify it reports `phase: "completed"`, then poll again.
420420

421421
A background agent may be used for the rewrite, but the current thread is responsible for verifying the five steps are complete before issuing the next poll. In practice, inline is usually faster and less error-prone.
422422

.claude/skills/impeccable/scripts/live-completion.mjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,14 @@ export function completionTypeForAcceptResult(eventType, acceptResult) {
55
if (acceptResult?.mode === 'error') return 'error';
66
return 'agent_done';
77
}
8+
9+
export function completionAckForAcceptResult(eventId, completionType, acceptResult) {
10+
const ack = { ok: true, type: completionType };
11+
if (acceptResult?.handled === true && acceptResult?.carbonize === true) {
12+
ack.final = false;
13+
ack.requiresComplete = true;
14+
ack.nextCommand = `live-complete.mjs --id ${eventId}`;
15+
ack.message = 'Carbonize cleanup must be verified, then the session must be completed explicitly before polling again.';
16+
}
17+
return ack;
18+
}

.claude/skills/impeccable/scripts/live-poll.mjs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import { execFileSync } from 'node:child_process';
1212
import path from 'node:path';
1313
import { fileURLToPath } from 'node:url';
14-
import { completionTypeForAcceptResult } from './live-completion.mjs';
14+
import { completionAckForAcceptResult, completionTypeForAcceptResult } from './live-completion.mjs';
1515
import { readLiveServerInfo } from './impeccable-paths.mjs';
1616

1717
// Node's built-in fetch (undici under the hood) enforces a 300s headers
@@ -169,14 +169,16 @@ Options:
169169
} catch (err) {
170170
event._completionAck = { ok: false, error: err.message };
171171
}
172-
if (!event._completionAck) event._completionAck = { ok: true, type: completionType };
172+
if (!event._completionAck) {
173+
event._completionAck = completionAckForAcceptResult(event.id, completionType, event._acceptResult);
174+
}
173175
}
174176

175177
// Second signal path: stderr banner in case the agent parses stdout
176178
// JSON but skips nested fields. One line is enough — the full checklist
177179
// is in reference/live.md.
178180
if (event._acceptResult?.carbonize === true) {
179-
process.stderr.write('\n⚠ Carbonize cleanup REQUIRED before next poll. See reference/live.md "Required after accept".\n\n');
181+
process.stderr.write('\n⚠ Carbonize cleanup REQUIRED before next poll. After cleanup, run live-complete.mjs --id ' + event.id + '. See reference/live.md "Required after accept".\n\n');
180182
}
181183

182184
// Print the event as JSON — the agent reads this from stdout

.claude/skills/impeccable/scripts/live-session-store.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ function rebuildSnapshotFromJournal(journalPath, id) {
137137
const entry = JSON.parse(line);
138138
if (!entry || typeof entry !== 'object') throw new Error('entry is not object');
139139
if (Number.isInteger(entry.seq)) nextSeq = Math.max(nextSeq, entry.seq + 1);
140-
snapshot = applyEvent(snapshot, entry, diagnostics);
140+
snapshot = applyEvent(snapshot, entry);
141141
} catch (err) {
142142
diagnostics.push({
143143
error: 'journal_parse_failed',

0 commit comments

Comments
 (0)