> ## Documentation Index
> Fetch the complete documentation index at: https://prism.ntecdev.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-38: Add Inquiry signal_type for inbound-pull / question semantics

> # ADR — Add `Inquiry` signal_type for inbound-pull / question semantics  **Status:** proposed (awaiting Frank's confirmation) · **Author:** Donna · **Date:** 20

<Info>**Status:** `proposed` · **ADR-38** · Filed 2026-04-30</Info>

# 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:

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 `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.
