mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 16:46:31 +03:00
Two of the three new findings, plus the bug that chasing them exposed in my own earlier fix. The third is mitigated rather than broken; details below. Failed accepts reported success: live/completion.mjs only classifies a result as `error` when it carries `mode: 'error'`. Everything else unhandled falls through to `agent_done` with an ok ack, which is deliberate for the documented fallback paths (two tests pin it) but wrong for a real failure. So `accept_receipt_conflict` reported success, and reference/live.md's `handled: false` without `mode` bullet told the agent to "read file, find markers, edit" — hand-applying a second accept on top of the one the receipt already recorded. The same hole swallowed `source_locked`, which is mine: the earlier commit made lock contention return clean JSON so the agent could retry, but the classifier turned that failure into agent_done/ok, so the accept was dequeued and silently lost. Mark genuine failures with `mode: 'error'` through one `operationFailure` helper, and give live.md a `mode: "error"` bullet with per-error guidance: retry the same command on `source_locked`, never hand-edit, and on a receipt conflict report what the session actually resolved to. The deliberate fallback and markers-not-found handoffs stay untouched. parallel-compact lane orchestration: `Promise.race` settles on the first *settlement*, so one lane failing fast rejected the whole first-variant step while two lanes were still on their way to succeeding. `Promise.any` now takes the first success and only a total wipeout is fatal, reporting every lane's reason. The tail step's `Promise.all` surfaced a raw lane error non-deterministically; `Promise.allSettled` now reports how many lanes failed and why. Added a `requestImpl` seam so lane orchestration is testable without a provider key. Not a defect: the browser releasing Accept before the source write. That is the intended optimistic design, and it is safe because poll-lanes ranks accept at priority 0 against generate at 2, so a queued accept is always leased before a generate the user queues afterwards, even if the generate arrived first. Its source write lands inside the poll script before the next generate preflights. That invariant is load-bearing and had no tests at all; poll-lanes.mjs now has a suite covering it plus lease and type filtering. Prepared with AI assistance under maintainer direction. Co-Authored-By: Claude <noreply@anthropic.com>
100 lines
3.8 KiB
JavaScript
100 lines
3.8 KiB
JavaScript
/**
|
|
* Tests for live/poll-lanes.mjs — which pending event a poll gets next.
|
|
* Run with: node --test tests/live-poll-lanes.test.mjs
|
|
*/
|
|
|
|
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import { eventPriority, selectAvailablePendingEvent } from '../skill/scripts/live/poll-lanes.mjs';
|
|
|
|
const entry = (type, seq, leaseUntil = 0, id = type + seq) => ({ event: { id, type }, leaseUntil, seq });
|
|
|
|
describe('poll lane priority', () => {
|
|
it('puts terminal user actions ahead of generation', () => {
|
|
for (const type of ['accept', 'discard', 'exit']) {
|
|
assert.ok(
|
|
eventPriority({ type }) < eventPriority({ type: 'generate' }),
|
|
`${type} must outrank generate`,
|
|
);
|
|
}
|
|
});
|
|
|
|
it('ranks unknown event types last rather than first', () => {
|
|
assert.ok(eventPriority({ type: 'something-new' }) > eventPriority({ type: 'generate' }));
|
|
assert.ok(eventPriority({}) > eventPriority({ type: 'generate' }));
|
|
});
|
|
|
|
// This is what makes the browser's optimistic Accept safe. The browser returns
|
|
// to PICKING as soon as /events durably journals the accept, before the source
|
|
// write happens, so the user can pick and hit Go while the accept is still
|
|
// queued. If that generate were leased first, its preflight would wrap source
|
|
// that still contains the previous session's variant markers.
|
|
it('delivers a queued accept before a generate the user queued afterwards', () => {
|
|
const selected = selectAvailablePendingEvent([
|
|
entry('accept', 1),
|
|
entry('generate', 2),
|
|
]);
|
|
assert.equal(selected.event.type, 'accept');
|
|
});
|
|
|
|
it('delivers the accept first even when the generate was queued earlier', () => {
|
|
const selected = selectAvailablePendingEvent([
|
|
entry('generate', 1),
|
|
entry('accept', 2),
|
|
]);
|
|
assert.equal(
|
|
selected.event.type,
|
|
'accept',
|
|
'priority must beat arrival order, or a slow poller preflights against stale source',
|
|
);
|
|
});
|
|
|
|
it('breaks ties within one lane by arrival order', () => {
|
|
const selected = selectAvailablePendingEvent([
|
|
entry('generate', 7),
|
|
entry('generate', 3),
|
|
]);
|
|
assert.equal(selected.seq, 3);
|
|
});
|
|
});
|
|
|
|
describe('poll lane availability', () => {
|
|
it('skips an entry whose lease is still held', () => {
|
|
const now = 1_000_000;
|
|
const selected = selectAvailablePendingEvent([
|
|
entry('accept', 1, now + 30_000),
|
|
entry('generate', 2),
|
|
], { now });
|
|
assert.equal(selected.event.type, 'generate', 'a leased accept must not be handed out twice');
|
|
});
|
|
|
|
it('re-offers an entry once its lease has expired', () => {
|
|
const now = 1_000_000;
|
|
const selected = selectAvailablePendingEvent([entry('accept', 1, now - 1)], { now });
|
|
assert.equal(selected.event.type, 'accept');
|
|
});
|
|
|
|
it('returns null when everything is leased', () => {
|
|
const now = 1_000_000;
|
|
assert.equal(selectAvailablePendingEvent([entry('accept', 1, now + 5_000)], { now }), null);
|
|
});
|
|
|
|
it('returns null for an empty queue', () => {
|
|
assert.equal(selectAvailablePendingEvent([]), null);
|
|
});
|
|
|
|
it('restricts delivery to the requested types', () => {
|
|
const entries = [entry('accept', 1), entry('generate', 2)];
|
|
assert.equal(selectAvailablePendingEvent(entries, { types: ['generate'] }).event.type, 'generate');
|
|
assert.equal(selectAvailablePendingEvent(entries, { types: new Set(['generate']) }).event.type, 'generate');
|
|
assert.equal(selectAvailablePendingEvent(entries, { types: ['steer'] }), null);
|
|
});
|
|
|
|
it('ignores an empty or absent type filter instead of starving the queue', () => {
|
|
const entries = [entry('generate', 1)];
|
|
assert.equal(selectAvailablePendingEvent(entries, { types: null }).event.type, 'generate');
|
|
assert.equal(selectAvailablePendingEvent(entries, {}).event.type, 'generate');
|
|
});
|
|
});
|