feat(events): close NDJSON schema gaps for downstream consumers (#63)#64
Conversation
Design doc closing the 5 asks + permission_granted nice-to-have from issue #63. Fixes schemaVersion to v1; defers reason field on permission_rejected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Embed EVENTS.md via Bun's text import so the schema ships with both `bun run dev` and the compiled single-file binary. Add `--schema-version` flag for quick version discovery. Register command in both index.ts and headless.ts entrypoints. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Now I have all the data. S = 255 for bug hunter, so N = 1. Dispatching 3 subagents (Security, Consistency, Bug Hunter) in parallel.## PR Review: #64 — feat(events): close NDJSON schema gaps for downstream consumers (#63) BLOCKER / MAJOR Findings1. The Granted event payload is built as 2. The 3.
MINOR Findings4.
5. The 6.
7.
8. Tool arguments ( 9. This test reads the source file as a string and checks for substring presence rather than importing and invoking 10. All tests read NIT Findings11. The cast 12. In the second error handler (prompt rejection path), the local 13. Repeated 14. Tests read the raw |
- next.ts: reverse spread order in Event.Granted publish so computed id always wins over any id that might appear in request (latent bug). - run.errors.ts: export SCHEMA_VERSION as the shared source of truth; events.ts and run.ts now import it instead of duplicating "1". - events.ts: drop unnecessary `as unknown as string` cast; md.d.ts already types the import as string. - run.ts: in the prompt-rejection catch, use classified.message for the local error string too, so session_complete.error matches session_error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed in
Intentionally skipping the rest:
All 67 tests green after the fixes. |
|
I'll start by fetching the PR metadata and per-file patches.Now let me examine the per-file patches to build the manifests. |
Review: NDJSON Schema v1 GapsOverall this is a well-structured PR. The error classification, schema versioning, and enriched permission events are clean. A few issues worth addressing: Bug: Subagent permission events silently dropped
Consider emitting subagent permission events the same way subagent tool_use events are emitted — check Bug:
|
- run.ts: emit permission_rejected/permission_granted for subagent sessions too (previously filtered out), matching the existing subagent tool_use pass-through. Fixes an asymmetry where a subagent's denied tool surfaced as a failed tool_use with no explaining permission_rejected event. - EVENTS.md: document that session_error is strictly for abnormal termination; session_complete.error may carry concatenated non-fatal errors without a preceding session_error. Alerting should key on session_error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed in
Skipping:
67/67 tests green. |
|
I'll start by fetching the PR metadata and per-file patches.Now let me build the three manifests.Now compute the total changed lines for bug hunter sharding:S = 263, which is ≤ 1000, so N = 1 bug-hunter shard. That means 2 + 1 = 3 subagents total. Let me extract the full patch data for each manifest:Now I have all the data. Step 4: dispatch 3 subagents (Security + Consistency + 1 Bug Hunter shard) in parallel.Now I'll merge, deduplicate, sort, and emit the final output. Let me process all three subagent results. Security subagent returned 2 findings. Deduplicating by
After deduplication, sorting by severity descending, then file, then line: Total: 15 findings, well under the 40 cap. No need to drop NIT or MINOR. Security Concerns
|
Review: NDJSON Schema v1 GapsOverall this is a solid, well-structured PR. The event schema additions are coherent, the classifier is clean, and the permission plumbing correctly threads tool ID + args through metadata. A few issues worth addressing: Bug:
|
…subagents - run.ts: replace process.exit(1) with process.exitCode = 1 in both error paths so stdout drains before the process exits. Piped consumers were at risk of missing the session_error / session_complete lines that describe why the session failed. - EVENTS.md: note that in JSON mode subagent sessions only emit tool_use events, so subagent sequenceNum counters only advance on tool_use — not shared across text/reasoning/tool_use the way the primary session counter is. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed in `ce225d5`:
Skipping:
67/67 green. |
Summary
Closes #63. Pins the NDJSON event stream to schema v1 and closes the five gaps + one nice-to-have the downstream aictrl executor flagged.
permission_rejectednow carriestool,input,callIDin a stable flat shape. Tool id + args are threaded throughPermissionNext.askmetadata from the per-tool execute closure.permission_grantedemitted symmetrically (newPermissionNext.Event.Grantedbus event fired from the allow-short-circuit path).session_erroremitted beforesession_completeon failure, with{reason, code, message}.reasonvocabulary:rate_limit,auth,timeout,oom,provider,unknown. Classifier inrun.errors.tshas unit tests.session_complete.errorkept for back-compat; marked deprecated in docs.session_startnow carriesschemaVersion: "1"and the fully resolvedpermissionsruleset (merge of agent + session rules).sequenceNumadded totext/reasoning/tool_use— monotonic per-session counter keyed onpart.sessionIDso subagent sessions have independent counters.aictrl eventssubcommand prints the bundledEVENTS.md(embedded via Bunwith { type: "text" }import so it works in the compiled single-file binary).--schema-versionprints1.Downstream-facing design notes live in
docs/superpowers/specs/2026-04-23-ndjson-schema-gaps-design.md; the execution breakdown is indocs/superpowers/plans/2026-04-23-ndjson-schema-gaps.md. Happy to drop those if they're noise.Caveats
permission_rejected.input/permission_granted.inputnow ship raw tool arguments into NDJSON (bash command strings, file contents for write/edit). This is what NDJSON event schema gaps for downstream observability consumers #63 explicitly asked for, but worth flagging — anyone piping the stream to durable logs should treat it accordingly.packages/cli/test/cli/run-schema-v1.test.tsare source-level assertions, matching the style ofrun-event-race.test.ts. A runtime-parse test would catch more regressions; happy to add if preferred.EVENTS.mdviawith { type: "text" }is Bun's documented behaviour but was not empirically verified (would require a full build).Test plan
🤖 Generated with Claude Code