OVOS-COMMON-QUERY-1: Common Query Pipeline Plugin Specification#40
OVOS-COMMON-QUERY-1: Common Query Pipeline Plugin Specification#40JarbasAl wants to merge 13 commits into
Conversation
Defines the scatter-gather question-answering pipeline plugin: question gate (§4), scatter-gather cycle (§5), skill-side protocol (§6), dispatch and Match construction (§7), answer-type metadata (§8), discovery protocol (§9), relation to intent classification (§10), pipeline positioning (§11), bus surface summary (§12), and conformance (§13). Key design decisions: - Pure-matcher plugin (PIPELINE-1 §7.0): Match.skill_id is the winning skill, not the plugin pipeline_id - Bus topics use ovos.common_query.* namespace consistently - Discovery via ping/pong per PIPELINE-1 §10 pattern - Dispatch on <skill_id>:common_query.question (intent_name, not a reserved name) - timed collection window with early-termination and skill-side extensions - no reserved intent_names (§2) Co-Authored-By: opencode/glm-5.1 <noreply@opencode.ai>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR introduces a complete specification for the OVOS common query pipeline plugin, a scatter-gather pure matcher that broadcasts questions to registered skills, collects responses, filters by confidence and denylists, and dispatches the highest-confidence skill result. ChangesOVOS Common Query Plugin Specification
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@common-query.md`:
- Around line 512-525: The fenced code block showing the session.pipeline array
lacks a language tag and triggers MD040; update the block by adding an
appropriate language identifier (e.g., yaml) to the opening fence so the block
containing session.pipeline and entries like "stop_high", "converse",
"template_high", "keyword_high", "common_query", "template_medium",
"keyword_medium", "fallback_medium", and "fallback_low" is labeled (for example
```yaml) to satisfy markdown linting and CI.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| ``` | ||
| session.pipeline: [ | ||
| "stop_high", # interrupt | ||
| "converse", # active-handler poll | ||
| "template_high", # registered intents (high) | ||
| "keyword_high", # registered intents (high) | ||
| "common_query", # scatter-gather question answering | ||
| "template_medium", | ||
| "keyword_medium", | ||
| ... | ||
| "fallback_medium", | ||
| "fallback_low" | ||
| ] | ||
| ``` |
There was a problem hiding this comment.
Add a language to the fenced code block to satisfy markdown linting.
Line 512 uses an unlabeled fenced block, which triggers MD040 and may fail docs CI.
Proposed fix
-```
+```yaml
session.pipeline: [
"stop_high", # interrupt
"converse", # active-handler poll
"template_high", # registered intents (high)
"keyword_high", # registered intents (high)
"common_query", # scatter-gather question answering
"template_medium",
"keyword_medium",
...
"fallback_medium",
"fallback_low"
]</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>
[warning] 512-512: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @common-query.md around lines 512 - 525, The fenced code block showing the
session.pipeline array lacks a language tag and triggers MD040; update the block
by adding an appropriate language identifier (e.g., yaml) to the opening fence
so the block containing session.pipeline and entries like "stop_high",
"converse", "template_high", "keyword_high", "common_query", "template_medium",
"keyword_medium", "fallback_medium", and "fallback_low" is labeled (for example
…ADME) New-spec metadata per AGENTS.md §2.1 exception: a new spec MAY combine its normative file with the metadata sweep. Additions: - appendix/rationale.md §4.9: bridge design rationale (minimalism, client isolation, session_id as MAY convenience, layer-2 injection, hardened-set trade-off) - appendix/divergences.md §5.8: HiveMind comparison (session_id vs destination-based routing) and conformance note - appendix/gaps.md: bridge-specific gaps (multi-hop cascade, wire format, health/heartbeat) - README.md: OVOS-BRIDGE-1 row in orchestrator stack table
…gaps, README)" This reverts commit 94cfa4a.
- rename `phrase` → `utterance` for consistency with PIPELINE-1 vocabulary - remove `lang` from all data payloads; language read from context.session.lang - remove `handles_speech` field and §6.1 (framework internal, not bus contract) - remove §8 answer-type metadata (defined nothing normative; reduces to one sentence in §4.1 about advisory hint fields) - move §10 "relation to intent classification" out of normative body - fix conf bug: `conf` is now conditional-required when `answer` is present; drop the "missing conf treated as 0" silent-discard rule - fix timing contradiction: separate initial window (RECOMMENDED 3s) from maximum window (RECOMMENDED 5s) so extensions have actual headroom - fix selection: drop reranker/ignore_skill_scores implementation detail; selection is "highest conf, deployer-defined tie-break" - add MUST NOT session mutation in §6.1 (common query is stateless) - add edge case: skill that sends only searching:true with no final response before max window is treated as decline - add edge case: duplicate final responses — first wins - fold §2 "reserved intent_name" into §2 intro paragraph - merge §5.5 "empty skill set" into §4.4 timing - fix ToC: sections now correctly list §2–§10 - conformance updated throughout; remove callback_data from skill MUST, remove reranker from plugin SHOULD Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ion, conf - Fix timing RECOMMENDEDs: initial 1s (was 3s), maximum 3s (was 5s); add note that voice-responsive deployments SHOULD keep initial window ≤1s - Add §4.5 multi-session response correlation: plugin MUST key collection state by session_id from context.session; cross-session responses MUST be discarded — was completely unspecified - Reframe §3 question gate as cost-optimisation pre-filter, not primary quality gate; confidence filter (§4.3) is the primary quality gate; gate-less deployments are explicitly conformant - Soften gate conformance: MUST NOT accept commands → SHOULD NOT accept unambiguous action commands; acknowledge the question/command boundary is fuzzy; note that over-acceptance is recoverable, under-acceptance is not - Add conf value range table in §4.3 (0.0–1.0 in four bands) so cross-skill values are interoperable - Add reranker SHOULD in §4.3 and conformance: plugin SHOULD use a reranker when available to rank surviving candidates instead of raw conf ordering - Note in §4.3 that conf is self-reported and uncalibrated across skills - Add streaming answer delivery to "does not define" in §1 - Update conformance throughout to reflect gate-optional framing, session-correlation MUST, and reranker SHOULD Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…window Fast-win threshold (§4.3 step 3): - plugin SHOULD close the collection window immediately when any denylist-surviving response exceeds a deployer-defined fast_win_threshold (RECOMMENDED 0.9) - listed as the second early-close condition in §4.4 alongside all-responded and single-skill Adaptive initial window via latency hints (§7): - ovos.common_query.pong gains optional latency_ms field — skill's expected response time in milliseconds - plugin SHOULD set the initial window to max(latency_ms) across registered skills (clamped to maximum window) rather than a fixed constant; unknown-latency skills fall back to the fixed RECOMMENDED - skill SHOULD include latency_ms in pong response §4.4 early-close conditions made explicit as a numbered list: 1. all-responded 2. fast-win 3. single-skill (special case of 1, made explicit) Conformance updated throughout. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ndler
Structural redesign to align with stop/converse/fallback patterns:
- common_query is now a reserved intent_name (PIPELINE-1 §7.3 registry)
- plugin bundles its own handler; Match.skill_id = plugin's pipeline_id
- two-phase architecture:
* match(): fast ping/pong poll ("wants_to_answer") — skills do local
keyword/vocab checks only, MUST NOT perform network/IO during pong
* handler (<pipeline_id>:common_query): dispatches <skill_id>:common_query
to claiming skills in parallel, collects full answers via reply
derivation, reranks, speaks best via ovos.utterance.speak
Previous broadcast+scatter model replaced:
- ovos.common_query.question (broadcast eval) → ovos.common_query.ping
- ovos.common_query.question.response (shared) → ovos.common_query.pong
(reply derivation, carries can_answer + latency_ms)
- winning dispatch → <skill_id>:common_query (plugin handler → skill)
skill responds with answer+conf via reply, MUST NOT speak
Key constraints:
- skill MUST NOT call ovos.utterance.speak; plugin handler speaks
- pong MUST be synchronous/local; no blocking I/O
- plugin MUST preserve claiming skill list between match and handler
- session keying (§5.3, §6) preserves multi-session isolation
Retained from previous version:
- question gate as optional cost-optimisation pre-filter (§4)
- fast-win threshold (§7.2 step 3)
- adaptive collection window from latency_ms (§7.3)
- conf range table (§7.2)
- reranker SHOULD (§7.2 step 4)
- pipeline positioning guidance (§9)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…iming_skills slot, handler.error - Resolve silence vs early-termination contradiction: drop 'prior pong history' early-close condition; poll window closes on sufficiency or timeout only; 'remain silent' guidance now consistent with §5.3 - Add normative pong latency bound: MUST complete within deployer-configured bound; RECOMMENDED 100ms - Carry claiming skill_ids in Match.slots as claiming_skills (§6) — removes reliance on in-process state, safe for distributed deployments - Specify answer response topic: <skill_id>.common_query.response (dotted form, reply derivation); was previously underspecified - Clarify <skill_id>:common_query sub-dispatches: direct plugin-to-skill bus messages, orchestrator does not participate, skills MUST NOT emit lifecycle signals - Fix §7.2 step 5: no-answer is expected outcome, not handler error; emit handler.complete + graceful ovos.utterance.speak response - Merge §7.4 into §7.2 step 4 'Selection and speaking'; remove as standalone - Remove duplicate topic table from §8; point to §10 bus surface - Add <skill_id>.common_query.response to §10 bus surface table - Conformance updated throughout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- §4: "emits an error" → "speaks graceful no-answer and completes normally" (contradicted §7.2 step 5 which reserves handler.error for crashes) - §7.2 step 4: drop unverified PIPELINE-1 §9.6 subsection number - §8 obligation 3: §7.4 → §7.2 step 4 (§7.4 was merged in previous commit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hing Core design change: match now does everything (ping/pong + answer collection + filtering + selection). Handler becomes trivial: read answer from Match.slots and speak it. When no answer survives confidence filtering, match returns None — pipeline continues to fallback naturally. Eliminates the need for any new PIPELINE-1 handler-lifecycle signal. Match.slots shape extended: answer, conf, answer_skill_id, claiming_skills. New §5 pre-caching optimisation: plugin MAY subscribe to utterance arrival event and begin scatter-gather in parallel with upstream pipeline stages. Cache keyed by session_id, TTL 10s on unclaimed entries, evicted on consumption. §11 pipeline positioning: documents latency profile explicitly; common_query is an inherently slow stage, should sit just before fallback. Pre-caching amortises cost but does not change worst-case. Bus surface updated: <skill_id>:common_query now sent during match, not by the handler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t correctness, slot trim
Address design-review findings:
- §2.1: name common query a deliberate exception to PIPELINE-1 §4.4
latency discipline (the answer IS the claim decision, so collection
cannot defer to the handler). Require match-timeout bound >= collection
ceiling or the stage is skipped mid-contest. Cite §4.4 by section.
- §5: rename to "early-start optimisation"; subscribe to the concrete
ovos.utterance.handle entry topic (PIPELINE-1 §9.1), not a vague event.
- §5.1: cache holds only RAW responses + utterance, never a selected
answer; all filtering/selection runs at match time against the LIVE
session — fixes the staleness hole where a pre-collected answer ignored
an upstream blacklist/session change. Discard cache on lang mismatch.
- §5.2: key cache by (session_id, utterance); evict on consumption and on
any new utterance; drop the arbitrary 10s TTL (leaked implementation).
- §6.1/§6.2/§7.1: add utterance echo as explicit correlation key on ping,
pong, and response; discard non-correlated messages — fixes the
race between concurrent utterances in one session.
- §6.2: reframe pong bound — plugin MUST enforce poll-window timeout,
skills SHOULD respond within bound (was an unenforceable skill MUST).
- §6: articulate ping/pong rationale (cheap local filter gating the
expensive full-answer path) so it is not cargo-cult.
- §7.2/§8: split MUST-support vs SHOULD-timing for early termination.
- §9: trim Match.slots to just {answer} — claiming_skills/answer_skill_id
were dead weight the trivial handler never read.
- Move tunable defaults to Appendix A, confidence ranges to Appendix B;
unclutters the normative body.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The gate was framed as merely optional. Make it a SHOULD: a plugin SHOULD apply a classifier or cheap short-circuit to skip the contest for non-question-like utterances (weather, music, timers, plain statements). A cheap up-front reject is the largest latency win for mixed traffic. Gate-less remains conformant — the confidence filter guarantees correctness — but pays the broadcast cost every utterance. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ssary, changelog) Non-normative companion content for the common query spec: - appendix/rationale.md §4.9: why match blocks (the answer is the claim decision), why None-on-no-answer keeps fallback alive, why ping/pong is a cheap filter not ceremony, why early-start caches only raw responses against the live session, and the gate as the largest latency win on mixed traffic. - appendix/comparisons.md §2.6: Mycroft CommonQuerySkill as the direct ancestor — same scatter-gather shape, but two-phase for a different reason (their bus-timeout management vs. our cheap-filter/expensive- answer split), contest in the pipeline not a skill, single plugin speaker. Alexa/Google resolve centrally and have no analogue. - GLOSSARY.md: common query, scatter-gather, wants-to-answer poll. - CHANGELOG.md: OVOS-COMMON-QUERY-1 v1 initial-draft entry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Companion issue: #41
Summary
Defines the common query pipeline plugin — a scatter-gather matcher that identifies question-like utterances, broadcasts them to registered question-answering skills, collects responses within a timed window, selects the best answer by confidence, and dispatches the winning skill to speak it.
What the spec covers
Match.skill_idis the winning skill, never the plugin's ownpipeline_id)ovos.common_query.questionbroadcast, timed collection window, early termination,searchingextension protocol<winning_skill_id>:common_query.questionovos.common_query.ping/ovos.common_query.pongKey design decisions
common_query.questionis a skill-owned intent name, not a reserved name — skills register it via INTENT-4 and receive dispatch normallysession.blacklisted_skillsexcludes skills from the scatter-gather pool