LearnNewsExamplesServices
Frontmatter
id17648
titleA declared schema default makes the service's contextual default unreachable
stateClosed
labels
bugaimodel-experienceagent-os
assigneesneo-opus-grace
createdAtAug 23, 2026, 9:37 PM
updatedAtAug 23, 2026, 10:14 PM
githubUrlhttps://github.com/neomjs/neo/issues/17648
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 23, 2026, 10:14 PM

A declared schema default makes the service's contextual default unreachable

Closed Backlog/active-chunk-19 bugaimodel-experienceagent-os
neo-opus-grace
neo-opus-grace commented on Aug 23, 2026, 9:37 PM

Context

Root-caused on #17646 by @neo-gpt-emmy, from a candidate I had raised, dropped on weak evidence, and re-opened. Carved out because it is a distinct mechanical defect with its own blast radius: #17646 asks a policy question (should every AGENT:* broadcast be quiet by default?), while this is a wiring bug that silently disables service-side defaults — and it affects a second field that #17646 never mentions.

The Problem

openApiValidator.mjs compiles every declared OpenAPI default into the Zod schema:

if (Object.hasOwn(schema, 'default')) {
    zodSchema = zodSchema.default(schema.default);
}

buildZodSchema then wraps non-required fields with .optional(), but Zod 4 still applies the inner default. Emmy's control:

z.object({wakeSuppressed: z.boolean().default(false).optional()}).parse({})
// → {wakeSuppressed: false}

So an omitted field arrives at the handler as its declared default, never as undefined. Any service that layers its own context-dependent default with ?? is then unreachable, because false ?? X is false and 'normal' ?? X is 'normal'.

Two live instances, both in add_message:

field schema service intent actual
wakeSuppressed default: false (openapi.yaml:2135) MailboxService.mjs:2417 — quiet for claim-class AGENT:* broadcasts never fires; every claim broadcast wakes every seat
priority default: "normal" (:2126) :2410 — operatorSteering ? 'high' : 'normal' never fires; operator-sent messages never get the high priority the design gives them

The priority one is the more interesting find: nobody reported it, and its symptom is the absence of an escalation rather than a visible fault. It was found only because the same root cause was being traced for wakeSuppressed — a second defect that would have kept working incorrectly indefinitely.

The Architectural Reality

The two layers each define a default and disagree about who owns it:

  • The schema default is static and documents an unconditional value.
  • The service default is computed from sender principal class and target — context a schema cannot express.

Declaring both is the bug, and the schema silently wins. This is not a Zod misuse: materialising a declared default is correct behaviour for the 31 other declared defaults in this document, where no service-side contextual default competes.

So the rule this ticket establishes: a request field may declare a schema default or have a service-side contextual default, never both. When the service computes the value from context, the schema must leave the field genuinely absent so ?? can see it.

The Fix

Remove the two competing declarations and let the service own them:

  • openapi.yaml — drop default: false from wakeSuppressed and default: "normal" from priority in the add_message request body; restate both descriptions to say the server computes the effective value when the field is omitted, and what it computes it from.
  • No change to openApiValidator.mjs. Suppressing default materialisation globally would alter all 31 other declared defaults to fix two fields — a systemic change to repair a local contract violation.

Contract Ledger Matrix

# Target surface Source of authority Before After Fallback Evidence
1 add_message.wakeSuppressed schema openapi.yaml:2133-2136 default: false no declared default service computes; omitted reaches ?? MailboxService.mjs:2417 unreachable today
2 add_message.priority schema openapi.yaml:2123-2126 default: "normal" no declared default service computes from sender class :2410 unreachable today
3 both descriptions same state a static default state that the server computes it, and from what none the description is what a caller reads

Acceptance Criteria

  • Parsing an add_message payload that omits wakeSuppressed yields an object without the key — asserted through the real buildZodSchema over the repository's own operation, not a hand-built Zod control, since the defect lives in how our document is compiled.
  • The same for priority.
  • priority reaches its service-side branch: with the field omitted, an agent-sent message stores normal and the operator-steering path is no longer short-circuited by the schema. Included because a fix targeting only wakeSuppressed would leave the second instance live, which is how the predecessor regression survived.
  • Explicit values still win: wakeSuppressed: false on a claim broadcast still wakes, priority: 'high' is still honoured. Verified red against a change that ignored caller input.
  • No other add_message field regresses — the remaining declared defaults in the document are untouched.

Out of Scope

  • Whether every AGENT:* broadcast should be quiet, not just claim-class — that is #17646's policy question and needs peer input. This ticket restores the default that already exists; it does not widen it.
  • The end-to-end observation that a claim-class AGENT:* broadcast is actually stored suppressed. Moved out of this ticket's Acceptance Criteria on 2026-08-23 after @neo-gpt-emmy's RA-2. It cannot be observed from a merge: the MC server runs from a built image, so the parser change only takes effect after a deploy-home update and recreate — and a close target whose ACs cannot all be met by its own PR is either auto-closed dishonestly or blocks a correct fix indefinitely. It is the wake-noise outcome, which #17646 already owns; this ticket owns the parser-observable cause. Not deferred-with-a-pointer, genuinely relocated.
  • Global suppression of OpenAPI default materialisation. Rejected above.
  • The other 31 declared defaults, none of which currently compete with a service-side ??.
  • healthcheck's wake-state ambiguity — #17647.

Avoided Traps

  • Fixing wakeSuppressed alone. priority has the identical defect two lines up and no reporter. The predecessor regression (#15987) survived precisely by fixing the instance in front of it, and this ticket would repeat that shape at one-field granularity.
  • Patching openApiValidator to skip defaults on optional fields. That changes 33 declared defaults to repair 2, and materialising a declared default is correct wherever no contextual default competes. The violation is in the document, not the compiler.
  • Keeping the schema default "for documentation". A caller reading default: false on a field whose real default depends on sender class and target is being told something false; that is worse than absent. The description carries the truth instead.
  • Trusting a hand-built Zod control as the acceptance evidence. z.object({x: z.boolean().default(false).optional()}) reproduces the mechanism but not our document; AC-1 must run through buildZodSchema over the real operation or it proves the wrong thing.

Decision Record impact

none — restores documented behaviour; establishes the schema-vs-service default rule in-code rather than in an ADR.

Structure-map gate: N/A — no file introduced or relocated.

Live latest-open sweep: checked latest 20 open issues at 2026-08-23T19:36Z; no equivalent found. A2A in-flight claim sweep: latest 50 all-state messages — @neo-gpt-emmy posted the root cause as "peer-role convergence input; no implementation claim", so the lane is unclaimed.

Related

#17646 (where this was root-caused; the policy question stays there) · #15987 (the claim-class quiet default this makes reachable again) · #17647 (the diagnostic blindness that made the cause hard to find)

Credit: root cause identified by @neo-gpt-emmy with an executable probe through the real schema.

Origin Session ID: eb671e6e-ca17-4a53-8069-64fd5885ce84

Retrieval Hint: query_raw_memories("openapi declared default zod materializes omitted field service contextual default unreachable wakeSuppressed priority")

tobiu referenced in commit 7f60856 - "fix(mcp): drop the schema defaults that shadow add_message's computed ones (#17648) (#17649) on Aug 23, 2026, 10:14 PM
tobiu closed this issue on Aug 23, 2026, 10:14 PM