mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-10 23:19:09 +02:00
fix(brain-sync): throttle + bound the detector push; empty-queue fast path
Review-army findings on the #2549 detector. (1) The preamble runs --once at every skill boundary, so an unthrottled retry paid a full network push attempt per boundary in exactly the steady states it targets (offline, broken auth) — a captive-portal push can block 30-75s against the header's "<1s when idle" promise. Attempts now stamp .brain-last-push-attempt and retry at most every 10 minutes; the push never prompts (GIT_TERMINAL_PROMPT=0) and bounds stalled transfers via git's low-speed limits (portable — stock macOS has no timeout binary). (2) Author-scoped: only gstack-brain-sync's own commits retry; a user's manual commit in ~/.gstack rides along on real drains as before, never auto-published by the detector. (3) Empty-queue fast path exits before the compute/rewrite python spawns — the steady state is now cheaper than the pre-wave truncation code. (4) The queue rewrite warns on failure instead of silently letting the status claim a drain that didn't happen, counts held unparseable lines, and collapses duplicate lines on rewrite. Throttle + delivery matrix cases added (37/37). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
8a4f4dce1c
commit
4bc5b4caf3
+45
-1
@@ -596,7 +596,51 @@ describe('#2549 queue integrity', () => {
|
||||
fs.chmodSync(path.join(tmpHome, 'security'), 0o700);
|
||||
}
|
||||
|
||||
// Receipts healthy: detector delivers.
|
||||
// Receipts healthy: detector delivers. The refused attempt above stamped
|
||||
// the 10-minute throttle (deliberately — refusals must not busy-loop the
|
||||
// network at every skill boundary), so model the interval passing.
|
||||
fs.writeFileSync(path.join(tmpHome, '.brain-last-push-attempt'), '0');
|
||||
expect(run(['gstack-brain-sync', '--once']).status).toBe(0);
|
||||
expect(git(['rev-list', '--count', 'origin/main..HEAD']).stdout.trim()).toBe('0');
|
||||
});
|
||||
|
||||
test('detector attempts are throttled to one per interval', () => {
|
||||
initWithMode('full');
|
||||
fs.mkdirSync(path.join(tmpHome, 'projects', 'p'), { recursive: true });
|
||||
fs.writeFileSync(path.join(tmpHome, 'projects/p/learnings.jsonl'), '{"skill":"a","ts":"2026-01-01T00:00:00Z"}\n');
|
||||
run(['gstack-brain-enqueue', 'projects/p/learnings.jsonl']);
|
||||
expect(run(['gstack-brain-sync', '--once']).status).toBe(0);
|
||||
|
||||
// Strand a commit behind a rejecting remote.
|
||||
const hook = path.join(bareRemote, 'hooks', 'pre-receive');
|
||||
fs.writeFileSync(hook, '#!/bin/sh\nexit 1\n');
|
||||
fs.chmodSync(hook, 0o755);
|
||||
fs.appendFileSync(path.join(tmpHome, 'projects/p/learnings.jsonl'), '{"skill":"b","ts":"2026-01-02T00:00:00Z"}\n');
|
||||
run(['gstack-brain-enqueue', 'projects/p/learnings.jsonl']);
|
||||
expect(run(['gstack-brain-sync', '--once']).status).toBe(0);
|
||||
fs.rmSync(hook);
|
||||
|
||||
// First empty-queue run: detector attempts (stamps the throttle), pushes.
|
||||
expect(run(['gstack-brain-sync', '--once']).status).toBe(0);
|
||||
const stamp1 = fs.readFileSync(path.join(tmpHome, '.brain-last-push-attempt'), 'utf-8');
|
||||
expect(Number(stamp1)).toBeGreaterThan(0);
|
||||
expect(git(['rev-list', '--count', 'origin/main..HEAD']).stdout.trim()).toBe('0');
|
||||
|
||||
// Strand another; an immediate second run must NOT attempt (stamp fresh).
|
||||
fs.writeFileSync(hook, '#!/bin/sh\nexit 1\n');
|
||||
fs.chmodSync(hook, 0o755);
|
||||
fs.appendFileSync(path.join(tmpHome, 'projects/p/learnings.jsonl'), '{"skill":"c","ts":"2026-01-03T00:00:00Z"}\n');
|
||||
run(['gstack-brain-enqueue', 'projects/p/learnings.jsonl']);
|
||||
expect(run(['gstack-brain-sync', '--once']).status).toBe(0);
|
||||
fs.rmSync(hook);
|
||||
const stampBefore = fs.readFileSync(path.join(tmpHome, '.brain-last-push-attempt'), 'utf-8');
|
||||
expect(run(['gstack-brain-sync', '--once']).status).toBe(0);
|
||||
// Throttled: stamp unchanged, commit still stranded.
|
||||
expect(fs.readFileSync(path.join(tmpHome, '.brain-last-push-attempt'), 'utf-8')).toBe(stampBefore);
|
||||
expect(Number(git(['rev-list', '--count', 'origin/main..HEAD']).stdout.trim())).toBeGreaterThan(0);
|
||||
|
||||
// Interval passed: delivers.
|
||||
fs.writeFileSync(path.join(tmpHome, '.brain-last-push-attempt'), '0');
|
||||
expect(run(['gstack-brain-sync', '--once']).status).toBe(0);
|
||||
expect(git(['rev-list', '--count', 'origin/main..HEAD']).stdout.trim()).toBe('0');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user