Skip to content

createPod permits agent-room and creates a 1-member DM pod (ADR-001 §3.10 / ADR-016 invariant 3) #805

Description

@lilyshen0722

POST /api/pods with type: 'agent-room' succeeds and produces a one-member DM-kind pod, violating ADR-001 §3.10 (DM pods are strictly 1:1 — exactly two members) at creation time.

Demonstration

Run against controllers/podController.ts using the existing podController.test.js harness (mocked Pod, so this captures controller behaviour):

createPod({ body: { name: 'Sneaky Room', type: 'agent-room' }, userId: 'creator' })
→ res.status  : never called      (no 400)
→ new Pod(…)  : { type: 'agent-room', members: ['creator'] }
→ save()      : called
→ res.json()  : called

Why it gets through

  • VALID_POD_TYPES (controllers/podController.ts:26) includes agent-room. The sibling allowlist at routes/agentsRuntime.ts:2554 omits both agent-room and agent-dm; this one omits only agent-dm, with no stated reason for the difference.
  • The gate at :383 therefore passes, and :387–395 constructs the pod with members: [req.userId] — one member.
  • Pod.ts's only pre-save hook (:148) pushes createdBy into members and enforces nothing about DM cardinality, so there is no model-level backstop on this path.

The guard exists — it is just never applied at creation

DM_POD_TYPES_GUARD is consulted in four places:

site path
controllers/podController.ts:477 join
routes/podInvites.ts:175 invite create
routes/podInvites.ts:242 invite redeem
routes/agentsRuntime.ts:2444 discovery type exclusion

Every entrance into a DM pod is guarded except the one that makes the pod.

Suggested fix

Apply DM_POD_TYPES_GUARD in createPod — refuse DM kinds with a 400 naming the correct rail (ensureAgentInPod / commonly_open_dm), matching how agentsRuntime's allowlist already behaves. Either that, or drop agent-room from podController's VALID_POD_TYPES so the two allowlists agree.

Note VALID_POD_TYPES in podController is also used at :279 by getPodsByType, a read filter — so narrowing the constant for a creation reason silently narrows a read endpoint. If the fix is "drop agent-room from the list," that side effect needs handling; adding the guard to createPod avoids it.

Provenance

Surfaced while reviewing #802, whose ADR-016 §Kind paragraph states the reasoning correctly — the allowlists omit DM kinds because "creating one through a generic create-pod endpoint would produce a 1-member pod violating the §3.10 two-member guard at birth" — and then notes podController permits agent-room as an unresolved asymmetry. It is not an asymmetry; it is that failure, reachable today.

Not verified

  • Live behaviour — unit-level only; no POST to production, and the PG mirror write was not traced.
  • Whether any agent-room rows created this way exist in production. Unmeasured, not unobserved.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions