Repository navigation
feat(OMN-20905): the Stop capture marks the prompts the operator typed, so decisions are taken from the bus - #2670
Merged
Merged
Conversation
…d, so decisions are taken from the bus RULING 2026-10-10T22:40:43Z: operator decisions and asks are extracted asynchronously from the bus, not by capture hooks. The content-capture producer now journals each prompt whose transcript origin is human as content_kind operator_prompt (with its prompt id and said_at), once per session; lane briefs (claude -p, turnOrigin sdk), scheduled prompts, task notifications, compaction summaries and subagent stops never are.
jonahgabriel
enabled auto-merge (squash)
October 11, 2026 00:36
jonahgabriel
pushed a commit
to OmniNode-ai/onex_change_control
that referenced
this pull request
Oct 11, 2026
) * evidence(OMN-20905): author OCC companion for OmniNode-ai/omniclaude#2670 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head b2b4d3fb666aef115727e44e9fdf59584b5db41a. * evidence(OMN-20905): self-bind OCC#13625 + rebind contract_sha256 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai>
Contributor
✅ Hostile Reviewer — PASSEDBlocking findings (critical/error): 0 Findings
Gate semantics (pilot phase)
Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524) |
PR omniclaude#2670 head b2b4d3f hand-edited the mirror src/omniclaude/hooks/contracts/capture_redaction.yaml to declare prompt_id and said_at as capture_verbatim on onex.cmd.omniintelligence.content-captured.v1. omnimarket owns that contract (OMN-18357); the mirror must equal the copy at the omnimarket rev uv.lock pins (1b1041574e98), which does not declare them. So "Registry Consistency" (scripts/validation/generate_event_registry.py --check) and Tests Gate (tests/hooks/test_capture_redaction_omn17959.py, 2 tests) failed with drift on ['topics']. This commit restores the mirror to its dev bytes. The producer still journals prompt_id and said_at; until omnimarket's owning contract declares them, the fan-out hashes them as undeclared fields, which is the contract's fail-safe default.
This was referenced Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ticket: OMN-20905. Companion: omnimarket#3745 (the bus consumer).
Operator RULING 2026-10-10T22:40:43Z: the operator's decisions and asks are extracted asynchronously from the bus, not by capture hooks. The bus must therefore say which prompts the operator typed.
Change
The existing Stop content capture (
hook_content_capture.py --kind stop) also journals, from the transcript, each prompt whose entry hasorigin.kind == "human"(not meta, not sidechain) ascontent_kind=operator_promptwith itsprompt_idandsaid_at, once per session (a marker of entry ids beside the turn state; the first Stop looks back at most an hour). Aclaude -plane brief (turnOriginsdk, no origin), a scheduled prompt, a task notification, a compaction summary and a subagent Stop never produce one. Why Stop and not UserPromptSubmit: the UserPromptSubmit payload carries identical fields for an operator prompt and a lane brief, and the transcript entry that distinguishes them is written only after that hook returns (measured on Claude Code 2.1.295). A message typed mid-turn, which never fires UserPromptSubmit, is recorded too. The redaction contract addsprompt_idandsaid_atas verbatim fields (identifiers and a timestamp, no content).No new hook, no settings change.
Tests
uv run pytest tests/unit/hooks/test_hook_operator_prompt_omn20905.py tests/unit/hooks/test_hook_content_capture_omn19551.py tests/hooks/test_capture_redaction_sync_omn18357.py tests/hooks/test_capture_redaction_omn17959.py -q: 76 passed. ruff clean.Lab: .201 dev lane bus, 2026-10-11T00:05:28Z. This branch's Stop capture was run on the operator's orchestrator session transcript and on a
claude -plane session; the hook-emit drainer published both toonex.cmd.omniintelligence.content-captured.v1; the omnimarket#3745 capture host on lanedevtook exactly one operator prompt ("Yes, to your recommendations", the operator's session) and appended its ledger row 22 s later; the lane session produced no operator_prompt record and no row (host handled=1, skipped=169).Evidence-Ticket: OMN-20905
Evidence-Source: OCC#13625