From d89dc326c25049816999bbf68782bf7086e73f95 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sun, 4 Oct 2026 06:50:17 +0000 Subject: [PATCH] test(auto-decide): the printed handoff may precede Step 0E's provenance log; replay census 37182865432; TODOS for two rotating census reds --- TODOS.md | 18 ++ test/ceo-mode-handoff.test.ts | 36 ++- ...decide-handoff-before-log-37182865432.json | 221 ++++++++++++++++++ test/helpers/native-auto-decide.ts | 12 +- test/helpers/touchfiles-data.ts | 2 +- 5 files changed, 282 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/auto-decide-handoff-before-log-37182865432.json diff --git a/TODOS.md b/TODOS.md index 51afbfc83..45218f795 100644 --- a/TODOS.md +++ b/TODOS.md @@ -137,6 +137,24 @@ Deferred from the approved severe fix wave (docs/designs/SEVERE_FIX_WAVE_2026_10 is `test/fixtures/auto-decide-handoff-line-e354.json`). Local paid trials after the repair: auto-decide-preserved 1/1, plan-ceo-mode-routing 1/1 (both modes); every session ran the helper. +- **plan-ceo-section-loading misses correctly worded stale-fill findings** — + censuses 37178734784 (65d94f2) and 37182865432 (44ef18c) failed + `hasStaleFillRaceFinding` although the review found the race. In 44ef18c it + named schedule S2 ("a read can fetch an old copy, pause, and only then put + it in the cache… every later reader gets stale data") and approved a + fill-admission guard. The detector is a regex family over phrasings; adding a + spelling per failure is the wrong fix. Bind the case to a structured finding + record (or an LLM judge with a fixed rubric) instead. 2 of the last 3 + censuses, 0 of the 16 before. Effort M. **Priority:** P2. +- **auq-matrix recommendation-substance judge rotates red** — census + 37182865432 scored plan-design-review's "A because the plan is thin + everywhere, so skipping dimensions mostly skips gaps" 3 < 4. The same case + was red in 5 of the 16 earlier censuses (37151477069 on main, + 36898545245, 36787269090, 36641820398, 36633323521) across skills and checks + (a two-`(recommended)` option count; office-hours substance). It is kind + `rule` but gates on one judge sample. Decide under EVAL_POLICY whether it is + a `judge` case (3 samples, mean) and supply pass-rate evidence before + changing the kind. Effort S. **Priority:** P2. - **Floor runner cannot grant an owned Edit when the TTY collapses spaces** — PR run 37176835584 (7249f01): plan-ceo-finding-floor timed out at 600 s with the native "Do you want to make this edit to gstack-test-plan-ceo-floor.md?" diff --git a/test/ceo-mode-handoff.test.ts b/test/ceo-mode-handoff.test.ts index dcf731055..2b89e855f 100644 --- a/test/ceo-mode-handoff.test.ts +++ b/test/ceo-mode-handoff.test.ts @@ -109,7 +109,8 @@ describe('native handoff evidence', () => { sent.tools.push(...handoff(sent.options.sessionId, loggedAt + 1000, `${CMD} "HOLD SCOPE" --auto`, AUTO_LINE)); expect(decide(sent)).toMatchObject({ option: 'HOLD SCOPE', annotation: AUTO_LINE, stateRecord: sent.options.stateEvidence.records[0] }); const { f: early } = attempt(); - early.tools.push(...handoff(early.options.sessionId, loggedAt - 5000, `${CMD} "HOLD SCOPE" --auto`, AUTO_LINE)); + const started = Date.parse(early.tools.find((e: any) => e.kind === 'result' && String(e.content).includes('SKILL_START_PROTO')).timestamp); + early.tools.push(...handoff(early.options.sessionId, started - 5000, `${CMD} "HOLD SCOPE" --auto`, AUTO_LINE)); expect(decide(early)).toBeNull(); const { f: changed, loggedAt: changedAt } = attempt(); changed.tools.push(...handoff(changed.options.sessionId, changedAt + 1000, `${CMD} "HOLD SCOPE" --auto`, AUTO_LINE)); @@ -143,6 +144,39 @@ describe('native handoff evidence', () => { } }); + test('census 37182865432: the printed handoff before the provenance log is the declaration', () => { + const captured = JSON.parse(fs.readFileSync(path.join(import.meta.dir, 'fixtures/auto-decide-handoff-before-log-37182865432.json'), 'utf8')); + const attempt = () => { + const f = structuredClone(captured); + const use = f.tools.find((e: any) => e.kind === 'use' && e.input?.command?.includes('gstack-question-log')); + const record = JSON.parse(/gstack-question-log '(\{[^\n]*\})'/.exec(use.input.command)![1]!); + record.source = 'agent'; + record.ts = f.tools.find((e: any) => e.kind === 'result' && e.toolUseId === use.toolUseId).timestamp; + f.options.stateEvidence = { questionId: 'plan-ceo-review-mode', preference: 'never-ask', records: [record] }; + return f; + }; + const decide = (f: any) => findNativeAutoDecision(f.transcript, f.tools, f.options); + // As captured, the closing "**Mode decided: HOLD SCOPE.**" chat also declares the mode. + expect(decide(attempt())).toMatchObject({ option: 'HOLD SCOPE' }); + const handoffOnly = () => { + const f = attempt(); + f.transcript.assistantMessages.find((m: any) => m.text.startsWith('**Mode decided:')).text = 'Wrapping up this invocation.'; + return f; + }; + expect(decide(handoffOnly())).toMatchObject({ option: 'HOLD SCOPE', annotation: AUTO_LINE }); + for (const [name, mutate] of Object.entries({ + 'handoff output altered': (f: any) => { f.tools.find((e: any) => e.kind === 'result' && e.content === AUTO_LINE).content = AUTO_LINE.replace('HOLD SCOPE', 'SCOPE EXPANSION'); }, + 'record names another mode': (f: any) => { f.options.stateEvidence.records[0].user_choice = 'SCOPE EXPANSION'; f.options.stateEvidence.records[0].recommended = 'SCOPE EXPANSION'; }, + 'later withdrawal': (f: any) => { f.transcript.assistantMessages.push({ sessionId: f.options.sessionId, timestamp: new Date(f.options.now - 1000).toISOString(), text: 'Correction: I withdraw this decision.' }); }, + 'missing record': (f: any) => { f.options.stateEvidence.records = []; }, + })) { + const f = handoffOnly(); mutate(f); expect(decide(f), name).toBeNull(); + } + const pending = attempt(); + pending.transcript.assistantMessages.find((m: any) => m.text.startsWith('**Mode decided:')).text = '**Mode pending: HOLD SCOPE.**'; + expect(decide(pending)).toBeNull(); + }); + test('an answered mode handoff establishes that mode posture, and only that mode', () => { const records = structuredClone(expansionCapture.records); const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ceo-mode-handoff-')); diff --git a/test/fixtures/auto-decide-handoff-before-log-37182865432.json b/test/fixtures/auto-decide-handoff-before-log-37182865432.json new file mode 100644 index 000000000..0a9b1646e --- /dev/null +++ b/test/fixtures/auto-decide-handoff-before-log-37182865432.json @@ -0,0 +1,221 @@ +{ + "source": "Periodic census 37182865432 (44ef18c), auto-decide-preserved slice 20: the model ran gstack-ceo-mode-handoff, then logged provenance as Step 0E orders; the detector required the handoff after the log and timed out.", + "options": { + "skillName": "plan-ceo-review", + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "commandStartedAt": 1791095476944, + "now": 1791095559635 + }, + "transcript": { + "status": "ready", + "calls": [], + "assistantMessages": [ + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "text": "Received. I have the draft plan for deterministic skill-list ordering as context, along with your instructions: this is a mode-only handoff, no review mode has been selected yet, and the audit record's user_choice and recommended fields plus the mode handoff line should carry the full selected mode name rather than a menu letter. I'll wait for your slash command before starting anything.", + "timestamp": "2026-10-04T06:31:16.610Z" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "text": "Starting the plan-ceo-review preamble now. Per your instructions, I'll scope this run to the mode decision only: skip the Office Hours offer and setup prompts, gather just enough plan context to recommend a mode, ask the four-mode question, then run the handoff and audit record.", + "timestamp": "2026-10-04T06:31:24.520Z" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "text": "Preamble checks out, and with Conductor session and question tuning active, I'll check mode preference and send decision briefs as prose. I'm deferring the routing-rules setup since you'll handle it separately and plan mode blocks CLAUDE.md edits anyway\u2014moving on to gather plan context.\n\n", + "timestamp": "2026-10-04T06:31:37.194Z" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "text": "I've gathered context: only the plan fixture exists in the repo, no remote, so the base branch defaults to `main`, and the saved preference (AUTO_DECIDE) means I'll go with my recommendation of HOLD SCOPE. Running the mode handoff now.\n\n", + "timestamp": "2026-10-04T06:32:05.754Z" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "text": "I'm defaulting to HOLD SCOPE review mode since this is a small, tightly-invariant fix (deterministic sort on an existing listing path, ~1-3 files) with no new approach needed\u2014focus will be on sort correctness (case handling, tie-breaking, enumeration-order tests). Recording provenance and wrapping up this invocation.\n\n", + "timestamp": "2026-10-04T06:32:19.720Z" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "text": "**Mode decided: HOLD SCOPE.** The substantive review has not started, per your request.\n\nWhat this run did:\n- **Preamble** ran healthy. Conductor session, interactive, question tuning on.\n- **Mode selection** resolved by your saved preference for the mode question, which returned AUTO_DECIDE, so no question was asked. The handoff command printed the auto-decided line above.\n- **Audit record** logged with question id `plan-ceo-review-mode`, user_choice and recommended both set to the full name HOLD SCOPE, auto_decided true.\n- **Telemetry** recorded with outcome abort, since the review was intentionally stopped after the mode step.\n\nWhat this run skipped, by your instruction:\n- The Office Hours offer. No design doc exists for this branch, so it would normally fire.\n- The routing-rules setup prompt from skill-start. It is marker-based and will fire again on the next healthy run. Plan mode would also have blocked the CLAUDE.md edit and commit.\n- Review Sections 1 to 11, the plan file report, and ExitPlanMode. Nothing was written to the plan file.\n\nWhen you resume, HOLD SCOPE routes through 0G complexity check, 0I temporal interrogation, then the full review sections. Points worth pressing then: byte-order versus case-insensitive sorting for mixed-case names, tie-breaking for names that differ only by case, and whether the tests truly vary directory enumeration order instead of relying on the filesystem.\n\nSTATUS: DONE\nNo durable learnings this session.", + "timestamp": "2026-10-04T06:32:34.635Z" + } + ] + }, + "tools": [ + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:25.439Z", + "toolUseId": "toolu_01L7uumE3CicSqLq5YF1knYj", + "kind": "use", + "name": "Bash", + "input": { + "command": "~/.claude/skills/gstack/bin/gstack-skill-start --skill \"plan-ceo-review\" --model \"claude\"", + "description": "Run gstack skill-start preamble" + }, + "messageId": "msg_011Cfgj9VVtgc1YPY6mmRiFm", + "requestId": "req_011Cfgj9VHEbELRBQiu2UADr" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:26.964Z", + "toolUseId": "toolu_01L7uumE3CicSqLq5YF1knYj", + "kind": "result", + "content": "SKILL_START_PROTO: 1\nBRANCH: main\nPROACTIVE: true\nPROACTIVE_PROMPTED: yes\nSKILL_PREFIX: false\nREPO_MODE: unknown\nSESSION_KIND: interactive\nCONDUCTOR_SESSION: true\nACTIVATED: yes\nFIRST_LOOP_SHOWN: yes\nFIRST_TASK: \nLAKE_INTRO: yes\nTELEMETRY: off\nTEL_PROMPTED: yes\nSESSION_ID: 1582-1791095486-11f777bc\nTEL_START: 1791095486\nEXPLAIN_LEVEL: default\nQUESTION_TUNING: true\nUPDATE_CHECK: false\nLEARNINGS: 0\nHAS_ROUTING: no\nROUTING_DECLINED: false\nVENDORED_GSTACK: no\nMODEL_OVERLAY: claude\nGSTACK_PLAN_MODE: active\nARTIFACTS_SYNC: off\nGSTACK_INSTRUCTION_BEGIN: routing-injection 1582-1791095486-11f777bc\ngstack works best when the project CLAUDE.md includes skill routing rules. If no CLAUDE.md exists in the project root, create it. Use AskUserQuestion:\n\n> gstack works best when your project's CLAUDE.md includes skill routing rules.\n\nOptions: A) Add routing rules to CLAUDE.md (recommended) B) No thanks, I'll invoke skills manually\n\nIf A: append this section to the end of CLAUDE.md, then commit it (`git add CLAUDE.md && git commit -m \"chore: add gstack skill routing rules to CLAUDE.md\"`):\n\n## Skill routing\n\nWhen the user's request matches an available skill, invoke it via the Skill tool. When in doubt, invoke the skill.\n\nKey routing rules:\n- Product ideas/brainstorming \u2192 invoke /office-hours\n- Strategy/scope \u2192 invoke /plan-ceo-review\n- Architecture \u2192 invoke /plan-eng-review\n- Design system/plan review \u2192 invoke /design-consultation or /plan-design-review\n- Full review pipeline \u2192 invoke /autoplan\n- Bugs/errors \u2192 invoke /investigate\n- QA/testing site behavior \u2192 invoke /qa or /qa-only\n- Code review/diff check \u2192 invoke /review\n- Visual polish \u2192 invoke /design-review\n- Ship/deploy/PR \u2192 invoke /ship or /land-and-deploy\n- Save progress \u2192 invoke /context-save\n- Resume context \u2192 invoke /context-restore\n- Author a backlog-ready spec/issue \u2192 invoke /spec\n\nIf B: run `/home/runner/.cache/gstack-paid-shard-JD3Soh/tmp/gstack-hermetic-1394-NpFf9B/skill-home-IidIe9/.claude/skills/gstack/bin/gstack-config set routing_declined true` and say they can re-enable with `/home/runner/.cache/gstack-paid-shard-JD3Soh/tmp/gstack-hermetic-1394-NpFf9B/skill-home-IidIe9/.claude/skills/gstack/bin/gstack-config set routing_declined false`. This only happens once per project.\nGSTACK_INSTRUCTION_END", + "isError": false + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:37.196Z", + "toolUseId": "toolu_01WANu5n8ZmUR9vrNDrNSBwU", + "kind": "use", + "name": "Read", + "input": { + "file_path": "/home/runner/.cache/gstack-paid-shard-JD3Soh/tmp/gstack-plan-count-DAXalf/PLAN.md" + }, + "messageId": "msg_011CfgjAEx4HP8MpqmQTz4Qf", + "requestId": "req_011CfgjADu3noWMS75Adfr5q" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:37.215Z", + "toolUseId": "toolu_01WANu5n8ZmUR9vrNDrNSBwU", + "kind": "result", + "content": "1\t# Draft: deterministic skill-list ordering\n2\t\n3\tUsers compare skill listings in scripts and reviews. Make the existing listing\n4\tpath sort registered skill names deterministically before rendering them.\n5\tKeep skill membership, aliases, metadata and text/JSON output formats unchanged.\n6\tCover mixed-case names and differing directory enumeration order with tests.\n7\t\n8\tThis draft is the review target, not the current branch. For this invocation,\n9\tI want only the review-mode decision; I will handle optional Office Hours and\n10\tsetup separately, and run the substantive review later. No review mode has\n11\tbeen selected. For this mode-only handoff, use the full selected mode name in\n12\tthe normal audit record's user_choice and recommended fields and in the skill's\n13\tnormal mode handoff line. A menu letter alone would not identify the chosen mode.", + "file": { + "filePath": "/home/runner/.cache/gstack-paid-shard-JD3Soh/tmp/gstack-plan-count-DAXalf/PLAN.md", + "content": "# Draft: deterministic skill-list ordering\n\nUsers compare skill listings in scripts and reviews. Make the existing listing\npath sort registered skill names deterministically before rendering them.\nKeep skill membership, aliases, metadata and text/JSON output formats unchanged.\nCover mixed-case names and differing directory enumeration order with tests.\n\nThis draft is the review target, not the current branch. For this invocation,\nI want only the review-mode decision; I will handle optional Office Hours and\nsetup separately, and run the substantive review later. No review mode has\nbeen selected. For this mode-only handoff, use the full selected mode name in\nthe normal audit record's user_choice and recommended fields and in the skill's\nnormal mode handoff line. A menu letter alone would not identify the chosen mode.", + "numLines": 13, + "startLine": 1, + "totalLines": 13 + }, + "isError": false + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:39.661Z", + "toolUseId": "toolu_016Dk1tbvmvWJFZPCZbBKtx5", + "kind": "use", + "name": "Bash", + "input": { + "command": "echo \"REMOTE: $(git remote get-url origin 2>&1)\"; echo \"HEAD_REF: $(git symbolic-ref refs/remotes/origin/HEAD 2>&1)\"; echo \"--- log\"; git log --oneline -30; echo \"--- stash\"; git stash list; echo \"--- files\"; ls -la; echo \"--- todos\"; grep -rn \"TODO\\|FIXME\\|HACK\\|XXX\" -l --exclude-dir=node_modules --exclude-dir=vendor --exclude-dir=.git . | head -30; echo \"--- TODOS.md\"; cat TODOS.md 2>/dev/null || echo \"(none)\"", + "description": "Audit repo state, remote, history and TODOs" + }, + "messageId": "msg_011CfgjAEx4HP8MpqmQTz4Qf", + "requestId": "req_011CfgjADu3noWMS75Adfr5q" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:41.663Z", + "toolUseId": "toolu_0153M6xQkpMgLtck4F849Qwh", + "kind": "use", + "name": "Bash", + "input": { + "command": "printf '%s' \"Select the plan-ceo-review mode for the deterministic skill-list ordering plan: SCOPE EXPANSION, SELECTIVE EXPANSION, HOLD SCOPE, or SCOPE REDUCTION\" | ~/.claude/skills/gstack/bin/gstack-question-preference --check \"plan-ceo-review-mode\" --summary-stdin; echo \"PREF_EXIT: $?\"", + "description": "Check saved preference for the mode question" + }, + "messageId": "msg_011CfgjAEx4HP8MpqmQTz4Qf", + "requestId": "req_011CfgjADu3noWMS75Adfr5q" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:44.535Z", + "toolUseId": "toolu_01QoUodomJaBeM9zZB5VKzoN", + "kind": "use", + "name": "Bash", + "input": { + "command": "~/.claude/skills/gstack/bin/gstack-context-recovery 2>&1 | head -40; echo \"--- design doc\"; SLUG=$(~/.claude/skills/gstack/browse/bin/remote-slug 2>/dev/null || basename \"$(git -C /home/runner/.cache/gstack-paid-shard-JD3Soh/tmp/gstack-plan-count-DAXalf rev-parse --show-toplevel 2>/dev/null || pwd)\"); BRANCH=main; DESIGN=$(~/.claude/skills/gstack/bin/gstack-design-doc-find \"$SLUG\" \"$BRANCH\" 2>/dev/null); [ -n \"$DESIGN\" ] && echo \"Design doc found: $DESIGN\" || echo \"No design doc found\"", + "description": "Recover context and check for design doc" + }, + "messageId": "msg_011CfgjAEx4HP8MpqmQTz4Qf", + "requestId": "req_011CfgjADu3noWMS75Adfr5q" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:45.415Z", + "toolUseId": "toolu_016Dk1tbvmvWJFZPCZbBKtx5", + "kind": "result", + "content": "REMOTE: error: No such remote 'origin'\nHEAD_REF: fatal: ref refs/remotes/origin/HEAD is not a symbolic ref\n--- log\n6e5f800 Seed review plan\n--- stash\n--- files\ntotal 20\ndrwx------ 3 runner runner 4096 Oct 4 06:31 .\ndrwxr-xr-x 7 runner runner 4096 Oct 4 06:31 ..\ndrwxr-xr-x 8 runner runner 4096 Oct 4 06:31 .git\n-rw-r--r-- 1 runner runner 1132 Oct 4 06:31 CLAUDE.md\n-rw-r--r-- 1 runner runner 826 Oct 4 06:31 PLAN.md\n--- todos\n--- TODOS.md\n(none)", + "isError": false + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:45.505Z", + "toolUseId": "toolu_0153M6xQkpMgLtck4F849Qwh", + "kind": "result", + "content": "AUTO_DECIDE\nPREF_EXIT: 0", + "isError": false + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:31:45.590Z", + "toolUseId": "toolu_01QoUodomJaBeM9zZB5VKzoN", + "kind": "result", + "content": "--- RECENT ARTIFACTS ---\n{\"skill\":\"plan-ceo-review\",\"event\":\"started\",\"branch\":\"main\",\"session\":\"1582-1791095486-11f777bc\",\"ts\":\"2026-10-04T06:31:26.989Z\"}\n--- END ARTIFACTS ---\n--- design doc\nNo design doc found", + "isError": false + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:32:05.755Z", + "toolUseId": "toolu_01JuPbmLq6ZmKbP3t91p9szw", + "kind": "use", + "name": "Bash", + "input": { + "command": "~/.claude/skills/gstack/bin/gstack-ceo-mode-handoff \"HOLD SCOPE\" --decisions \"none\" --auto", + "description": "Run gstack CEO mode handoff for HOLD SCOPE" + }, + "messageId": "msg_011CfgjBbpD8J6519jkqvLre", + "requestId": "req_011CfgjBbYqDtppjsWAGqNoo" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:32:11.420Z", + "toolUseId": "toolu_01JuPbmLq6ZmKbP3t91p9szw", + "kind": "result", + "content": "Auto-decided review mode \u2192 HOLD SCOPE (your preference). Change with /plan-tune. Approved decisions: none.", + "isError": false + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:32:20.892Z", + "toolUseId": "toolu_01PbxZacUu8Ph611URXMobAZ", + "kind": "use", + "name": "Bash", + "input": { + "command": "~/.claude/skills/gstack/bin/gstack-question-log '{\"skill\":\"plan-ceo-review\",\"question_id\":\"plan-ceo-review-mode\",\"question_summary\":\"Select plan-ceo-review mode for deterministic skill-list ordering plan\",\"category\":\"routing\",\"door_type\":\"two-way\",\"options_count\":4,\"user_choice\":\"HOLD SCOPE\",\"recommended\":\"HOLD SCOPE\",\"auto_decided\":true,\"session_id\":\"1582-1791095486-11f777bc\"}'; echo \"QLOG_EXIT: $?\"", + "description": "Log auto-decided mode question to audit record" + }, + "messageId": "msg_011CfgjDWBvJPKDwNcYbjB7h", + "requestId": "req_011CfgjDVy2SFveysWKw5SbU" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:32:22.625Z", + "toolUseId": "toolu_01RKKa2pmNcBXzN8VTEWWaM6", + "kind": "use", + "name": "Bash", + "input": { + "command": "~/.claude/skills/gstack/bin/gstack-skill-end --skill \"plan-ceo-review\" --outcome abort --session-id \"1582-1791095486-11f777bc\" --tel-start \"1791095486\" --used-browse no --error-message \"\" --failed-step \"\" 2>/dev/null || true; echo \"TEL_EXIT: $?\"", + "description": "Run skill-end telemetry for the mode-only run" + }, + "messageId": "msg_011CfgjDWBvJPKDwNcYbjB7h", + "requestId": "req_011CfgjDVy2SFveysWKw5SbU" + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:32:23.792Z", + "toolUseId": "toolu_01PbxZacUu8Ph611URXMobAZ", + "kind": "result", + "content": "QLOG_EXIT: 0", + "isError": false + }, + { + "sessionId": "1d84eb71-de32-4e99-a62e-9046d0850c10", + "timestamp": "2026-10-04T06:32:23.918Z", + "toolUseId": "toolu_01RKKa2pmNcBXzN8VTEWWaM6", + "kind": "result", + "content": "SKILL_END: recorded outcome=abort duration_s=57\nTEL_EXIT: 0", + "isError": false + } + ] +} diff --git a/test/helpers/native-auto-decide.ts b/test/helpers/native-auto-decide.ts index f043e3a9f..eaa948142 100644 --- a/test/helpers/native-auto-decide.ts +++ b/test/helpers/native-auto-decide.ts @@ -47,10 +47,11 @@ function modeField(line: string): { value: string; completed: boolean } | null { const match = /^(?:(?:Correction|Actually|Update):\s*)?(?