Skip to main content
Status: proposed · ADR-38 · Filed 2026-04-30

ADR — Add Inquiry signal_type for inbound-pull / question semantics

Status: proposed (awaiting Frank’s confirmation) · Author: Donna · Date: 2026-04-30

Context

Backend signal_type enum has 8 values today, all of which are either outbound declarations or system events:
ValueSemantics
Acknowledgmentoutbound — “got it”
ReviewCompletedoutbound — “I reviewed your thing”
ReviewRequestedoutbound — “please review THIS deliverable”
StatusUpdateoutbound — “here’s what I did”
TaskAssignedoutbound — “do this”
MasterPreemptedsystem event
PeerJoinedsystem event
PeerLeftsystem event
None of the eight expresses “I’m asking you something, please respond.” Three stretched-fit instances have now been logged in project_signal_vocab_tracking (Desiree’s memory), crossing Frank’s 3-instance promote-to-spec trigger:
  1. 2026-04-29 roll-call (Donna → 6 agents) — used ReviewRequested as the closest fit. Recipients had to infer “this isn’t a code review request” from the payload.
  2. 2026-04-29 Lafonda → Donna design question — used StatusUpdate with payload.cat="ASK" workaround. The wire type said “here’s an update” while the payload said “please answer”.
  3. 2026-04-30 Desiree → Texi “check status” test — used StatusUpdate after ping was rejected. Same workaround pattern.
Senders are reaching for the closest declaration type, not the correct intent. The taxonomy gap is real and recurring.

Decision

Add Inquiry as a single new signal_type.
  • Backend signal_type Pydantic + DB CHECK constraint extended to 9 values: existing 8 + Inquiry.
  • derive_category defaults InquiryASK.
  • mcp-node signalCache.DEFAULT_CATEGORY_BY_TYPE adds the same mapping so the bell preview categorizes correctly.
  • Sub-flavors are tagged in payload via convention, not enum:
    • payload.kind = "status_request" for roll-calls
    • payload.kind = "design_question" for Q&A
    • payload.kind = "ping" for liveness probes
    • any sender-defined value for novel uses.
Status: proposed. Frank confirms before code lands.

Rationale

  • One type, payload-typed sub-flavors. Every observed instance reduces to a single wire intent: “I’m pulling info, please respond.” Splitting into multiple wire types (StatusRequest + Question + Ping + …) trades vocab clarity for taxonomy churn — every new inquiry flavor would otherwise propose a new enum value.
  • Pairs cleanly with existing Acknowledgment. The receive-respond loop becomes InquiryAcknowledgment (or StatusUpdate if a status report is the natural reply).
  • Maps to ASK category. Operator-facing bell behavior is correct by default; no payload.cat workaround needed for the new type.
  • Small surface change. One enum value, one Pydantic update, one DB CHECK constraint, one mcp-node mapping. No payload schema changes required.

Alternatives considered

A. Two new types — StatusRequest + Question

Pros: each wire type maps to a specific intent; future routing or automation could dispatch on type alone. Cons: line between “status request” and “question about your status” is genuinely fuzzy — Lafonda’s Q (#2) is closer to a design question; Desiree’s #3 is closer to a status pull but sits in the same family. Two types invite a third (Ping?) and we’re back to enum churn for flavor distinctions that should live in payload. Rejected: pays its complexity tax up front for benefit we don’t have a use case for yet (no router/automation dispatching on signal_type beyond category derivation).

B. Generic Question

Pros: most natural English. Pros same as Inquiry. Cons: collides slightly with HTTP/REST notion of “question vs command”; “inquiry” reads as more system-y. Bikeshed-grade. Either name works; Inquiry slightly preferred for system-y feel and because it generalizes to non-question pulls (status request without a literal ?).

C. Do nothing — keep stretching ReviewRequested / StatusUpdate

Pros: zero code change. Cons: payload semantics keep drifting from wire type; receivers can’t trust signal_type for routing; observed friction is non-zero (Frank asked the question; Desiree noticed the pattern). 3-instance trigger is the agreed criterion. Rejected.

D. Generic Message / Communication catch-all

Pros: solves all future taxonomy gaps in one stroke. Cons: defeats the entire point of having a typed enum. Receivers would have to read every payload to know the intent. Rejected.

Implementation

StepSurfaceCodeNotes
1Backend Pydanticbackend/app/schemas/signal.py (signal_type Literal)Add "Inquiry" to the union
2Backend DBnew alembic migrationDrop + recreate the signal_type CHECK constraint with 9 values
3Backend servicebackend/app/services/signal_service.py:_DEFAULT_CATEGORY_BY_TYPE"Inquiry": "ASK"
4mcp-nodemcp-node/src/signalCache.ts:DEFAULT_CATEGORY_BY_TYPEInquiry: "ASK"
5DocsSPEC-052 §3 amendment + signal-mesh.mdxAdd Inquiry row to taxonomy table
Steps 1–3 touch backend files heavily modified by Porsche for SPEC-056 (signal_service.py). Defer until SPEC-056 lands on main; track in a TODO. Step 4 (mcp-node) can land independently but is no-op until backend accepts the new type. Step 5 (docs) follows the code per feedback_doc_refresh_on_commit.

Open question for Frank

Inquiry vs Question — bikeshed-grade name choice. Default to Inquiry unless you prefer Question. Same semantics either way.
Last modified on May 18, 2026