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:
| Value | Semantics |
|---|
Acknowledgment | outbound — “got it” |
ReviewCompleted | outbound — “I reviewed your thing” |
ReviewRequested | outbound — “please review THIS deliverable” |
StatusUpdate | outbound — “here’s what I did” |
TaskAssigned | outbound — “do this” |
MasterPreempted | system event |
PeerJoined | system event |
PeerLeft | system 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:
- 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.
- 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”.
- 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 Inquiry → ASK.
- 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 Inquiry → Acknowledgment (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
| Step | Surface | Code | Notes |
|---|
| 1 | Backend Pydantic | backend/app/schemas/signal.py (signal_type Literal) | Add "Inquiry" to the union |
| 2 | Backend DB | new alembic migration | Drop + recreate the signal_type CHECK constraint with 9 values |
| 3 | Backend service | backend/app/services/signal_service.py:_DEFAULT_CATEGORY_BY_TYPE | "Inquiry": "ASK" |
| 4 | mcp-node | mcp-node/src/signalCache.ts:DEFAULT_CATEGORY_BY_TYPE | Inquiry: "ASK" |
| 5 | Docs | SPEC-052 §3 amendment + signal-mesh.mdx | Add 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.