Repository navigation
test(denkraum): cover CLI stop signal drain budgets #1838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -441,7 +441,7 @@ Stand 15.10.: Testmodule der vier Nähte durch SLIM-M1/S1/A1/P1 ausgelagert (SLI | |
| | V16-CHANGELOG-b | [Archiv: Historie][historie] | bestehender Owner | V16-CHANGELOG-a | Server | C | Erledigt #861 (merged 2026-10-09T15:02:01Z) | siehe Archiv | – | | ||
| | V16-RELEASE | Tag v1.6.0 (Beta-Regel x.y.0) | Nutzer | Z1 (bis DR-17), V16-KI30 (Fix-Abnahme), D5-GUARD, V16-UPD-CANCEL, V16-06, V16-CHANGELOG; #728 gemergt | PC | – | Erledigt: Tag v1.6.0 = d2582ceb (09.10. 23:22Z), release.yml 38004103979 grün, latest.json anonym 1.6.0, PC installiert; ersetzt: Freigabe: Nutzer 09.10. ~19:42Z an Root; Tag durch Root nach Merge dieses PRs (V16-RELEASE-PREP); ersetzt: Geplant: E2/E3 beantwortet; konkrete Freigabe dieses Releases weiterhin offen | jeder Release braucht Nutzerfreigabe; Environment release mit Required Reviewer Cuarroc am 09.10. per gh api bestätigt; danach Release-Pipeline grün | – | | ||
| | V16-FU | Nachläufer aus v1.6.0-Reviews und Release-Prüfung | Stabschef | v1.6.0 veröffentlicht (V16-RELEASE) | Server | B/C je Punkt | Erledigt 10.10.: SRV-2/SRV-5-Portschutz #931, SRV-3 #952, OWN-3 #930, NOT-1 und R912-FU-1 #941, NOT-2/NOT-3 #928, SRV-4 #927, REL-3 #926, REL-4 #929, R910-FU #937, R889-FU #899 (09.10.); Rest verschoben nach V16-FU-2; ursprünglich: Offen: R908-FU-1 (Wiring-Test stop→limitDrainForSignal), R908-FU-2 (Drain-Kommentar/Idempotenz); R912-FU-1 (existed-Flag statt stat, io-Seam); R910-FU, R896-FU, R899-FU K2, R889-FU; REL-3 (scripts/release.cmd veraltet), REL-4 (Rollback/releases-latest), NOT-1/2/3, SRV-2..5, OWN-3 | je Punkt eigenes Paket mit eigener Abnahme | – | | ||
| | V16-FU-2 | Rest aus V16-FU: SRV-5 gegenseitige Authentifizierung (laut #931 weiterhin geparkt), R908-FU-1 (Wiring-Test stop→limitDrainForSignal), R908-FU-2 (Drain-Kommentar/Idempotenz), R896-FU, R899-FU K2 | Stabschef | V16-FU | Server | B/C je Punkt | Geplant: nicht disponiert; ob schon anderswo erledigt: Unbekannt (zu prüfen) | je Punkt eigenes Paket mit eigener Abnahme | – | | ||
| | V16-FU-2 | Rest aus V16-FU: SRV-5 gegenseitige Authentifizierung (laut #931 weiterhin geparkt), R908-FU-1 (Wiring-Test stop→limitDrainForSignal), R908-FU-2 (Drain-Kommentar/Idempotenz), R896-FU, R899-FU K2 | Stabschef | V16-FU | Server | B/C je Punkt | In Arbeit: Teillieferung R908-FU-1 nach Merge von #1838: Wiring-Test am echten CLI-Einstieg für Linux-SIGTERM/SIGHUP und prozessseitig emittiertes SIGBREAK; kein nativer Windows-Signalnachweis. Neuer Kopf wartet auf erneute Root-Abnahme. SRV-5 gegenseitige Authentifizierung bleibt geparkt; R908-FU-2, R896-FU und R899-FU K2 bleiben offen | je Punkt eigenes Paket mit eigener Abnahme | – | | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The fresh replacement text still mixes mutually exclusive states: it describes R908-FU-1 as delivered “after merge of #1838” and then says the new head is awaiting Root acceptance. Once this commit is merged, that acceptance cannot still be pending, so the canonical row immediately becomes stale; retain the delivered scope and outstanding sibling work but remove the pre-merge approval status. AGENTS.md reference: AGENTS.md:L139-L139 Useful? React with 👍 / 👎. |
||
| | V16-NACHBEOB | Zwei Wochenmessungen und 40 Queue-Läufe; Messgrößen-Leitfaden | Stabschef | v1.6.0 | Server | C | Verschoben; KI-30-Schluss (#874: 42 Queue-Läufe ab 09.10., 0 KI-30) liegt vor, sein Fenster weicht vom Originalkriterium (Fenster ab #518, 05.10.) ab — Abgleich: Unbekannt (zu prüfen); zwei Wochenmessungen ohne vollständigen Fensterbeleg | Wochenberichte BENCH-01/02 im Ticket | b8b16ec8 | | ||
|
|
||
| KI-30-Quellenkonflikt (Basis `03542ef`, geprüft 09.10.): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,14 +32,14 @@ async function freePort() { | |
| const { port } = probe.address(); await new Promise(r => probe.close(r)); return port; | ||
| } | ||
| // freePort() can race with another binder; retry EADDRINUSE ("konnte nicht starten") on a fresh port, like server-stop/lifecycle. | ||
| async function startEntry(t, file, { webhook = false, args = [] } = {}) { | ||
| async function startEntry(t, file, { webhook = false, args = [], ipc = false } = {}) { | ||
| for (let attempt = 1; ; attempt++) { | ||
| const port = await freePort(); | ||
| const env = { ...process.env, DECISION_DESK_STATE: file, DECISION_DESK_PORT: String(port), DECISION_DESK_ROOT_AGENT_ID: 'root-test', | ||
| DECISION_DESK_ROOT_RECEIPT_TOKEN: strongSecret(), DECISION_DESK_WEBHOOK_SECRET: strongSecret() }; | ||
| delete env.DECISION_DESK_WEBHOOK_URL; | ||
| if (webhook) env.DECISION_DESK_WEBHOOK_URL = 'https://agentsroom.dev/api/triggers/t_abc123'; | ||
| const child = spawn(process.execPath, [...args, entry], { env, stdio: ['ignore', 'pipe', 'pipe'] }); | ||
| const child = spawn(process.execPath, [...args, entry], { env, stdio: ['ignore', 'pipe', 'pipe', ...(ipc ? ['ipc'] : [])] }); | ||
| const out = { stdout: '', stderr: '' }, waiters = []; | ||
| const feed = (key, d) => { out[key] += d; for (const w of waiters) w(); }; | ||
| child.stdout.on('data', d => feed('stdout', d)); child.stderr.on('data', d => feed('stderr', d)); | ||
|
|
@@ -95,20 +95,33 @@ test('DRSEC-G4b: SIGTERM lets an in-flight request finish within the budget and | |
| assert.ok(await missing(`${file}.owner`)); | ||
| }); | ||
|
|
||
| test('DRSEC-G4b: SIGTERM with a notification send that never answers prints one short line and exits non-zero and keeps the owner record', { skip: posixOnly }, async t => { | ||
| const dir = await workdir(t), file = join(dir, 'ledger.json'), store = new DeskStore(file, { rootAgentId: 'root-test' }); | ||
| await store.putQuestion(question('q1')); await store.migrate((await store.read()).revision); | ||
| await store.answer({ questionId: 'q1', questionRevision: 1, expectedAnswerId: null, requestId: 'req1', action: 'answer', selected: ['a'], note: 'x' }); | ||
| await store.close(); | ||
| // The webhook transport is the global fetch; this preload makes it announce itself and never settle. | ||
| const preload = join(dir, 'hang-fetch.mjs'); | ||
| await writeFile(preload, "globalThis.fetch = () => { process.stdout.write('SEND-STARTED\\n'); return new Promise(() => {}); };\n"); | ||
| const run = await startEntry(t, file, { webhook: true, args: ['--import', pathToFileURL(preload).href] }); | ||
| assert.equal(await run.output(/SEND-STARTED/), true); | ||
| run.child.kill('SIGTERM'); | ||
| const result = await within(run.done, 20000); | ||
| assert.equal(result.code, 1, result.stderr); | ||
| assert.equal(result.stderr.trim().split('\n').length, 1, result.stderr); | ||
| assert.match(result.stderr, /^Entscheidungsseite: Beenden fehlgeschlagen: DRAIN_TIMEOUT$/m); | ||
| assert.equal(await missing(`${file}.owner`), false, 'a stuck send keeps the owner record (intended)'); | ||
| }); | ||
| for (const signal of ['SIGTERM', 'SIGHUP', 'SIGBREAK']) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because this commit completes the R908-FU-1 stop-to-drain wiring tests, AGENTS.md reference: AGENTS.md:L139-L139 Useful? React with 👍 / 👎. |
||
| test(`DRSEC-G4b: ${signal} with a notification send that never answers prints one short line and exits non-zero and keeps the owner record`, { skip: posixOnly }, async t => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On Windows, expanding the former single SIGTERM test into this loop introduces two additional tests, for SIGHUP and SIGBREAK, that are skipped via AGENTS.md reference: AGENTS.md:L33-L37 Useful? React with 👍 / 👎. |
||
| const dir = await workdir(t), file = join(dir, 'ledger.json'), store = new DeskStore(file, { rootAgentId: 'root-test' }); | ||
| await store.putQuestion(question('q1')); await store.migrate((await store.read()).revision); | ||
| await store.answer({ questionId: 'q1', questionRevision: 1, expectedAnswerId: null, requestId: 'req1', action: 'answer', selected: ['a'], note: 'x' }); | ||
| await store.close(); | ||
| // The webhook transport is the global fetch; this preload makes it announce itself and never settle. | ||
| const preload = join(dir, 'hang-fetch.mjs'); | ||
| // POSIX cannot deliver SIGBREAK. Bridge only that OS event through Node's public process emitter; | ||
| // this exercises the real CLI listener and stop closure, without claiming Windows delivery coverage. | ||
| await writeFile(preload, "globalThis.fetch = () => { process.stdout.write('SEND-STARTED\\n'); return new Promise(() => {}); };\n" | ||
| + "process.on('message', signal => { if (signal === 'SIGBREAK') process.emit('SIGBREAK', 'SIGBREAK'); });\n"); | ||
| const run = await startEntry(t, file, { webhook: true, args: ['--import', pathToFileURL(preload).href], ipc: signal === 'SIGBREAK' }); | ||
| assert.equal(await run.output(/SEND-STARTED/), true); | ||
| const started = performance.now(); | ||
| if (signal === 'SIGBREAK') run.child.send(signal); | ||
| else assert.equal(run.child.kill(signal), true); | ||
| const result = await within(run.done, 20000); | ||
| const elapsed = performance.now() - started; | ||
| t.diagnostic(`${signal} drain: ${elapsed.toFixed(0)} ms`); | ||
| assert.equal(result.code, 1, result.stderr); | ||
| assert.equal(result.stderr.trim().split('\n').length, 1, result.stderr); | ||
| assert.match(result.stderr, /^Entscheidungsseite: Beenden fehlgeschlagen: DRAIN_TIMEOUT$/m); | ||
| assert.equal(await missing(`${file}.owner`), false, 'a stuck send keeps the owner record (intended)'); | ||
| // The specified totals are 6 s for SIGTERM and 4 s for console-close signals. A 500 ms lower | ||
| // tolerance and a 1.5 s upper margin distinguish those budgets without increasing either one. | ||
| const [min, max] = signal === 'SIGTERM' ? [5500, 7500] : [3500, 5500]; | ||
| assert.ok(elapsed >= min && elapsed < max, `${signal} drain must take ${min}–${max} ms, got ${elapsed} ms`); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The report embedded in commit AGENTS.md reference: AGENTS.md:L119-L125 Useful? React with 👍 / 👎. |
||
| }); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This V16-FU-2/R908-FU-1 change now also records an unrelated
selftest-win-signalfailure from PR #1835 and creates a separate follow-up assignment, even though the package report scopes the change to CLI drain coverage and claims that only the drain test changed. Keeping this independent CI investigation here bundles two packages and leaves the report, review classification, and evidence describing a different delta; move the incident record to its own package.AGENTS.md reference: AGENTS.md:L13-L17
Useful? React with 👍 / 👎.