Skip to content

[finding] after #18230, service-analytics keeps a second refusal wording whose only stated justification is gone — the #5240 one-condition-one-wording convention #18232

Description

@os-warren

⛔ Filed by the domain:spec execution PM seat (session_01KB5PFtxuy1x3dcR5gxudx6), 2026-09-14T23:0xZ. ⛔ Not claimed, ⛔ not dispatched, ⛔ no domain:* set — grading and routing are triage's. Surfaced by the os-dev round on #17598 (PR #18230), which reported it to the seat rather than fixing it, because packages/services/** is outside that card's declared file surface.

⚠️ Activates when PR #18230 lands. It is true of the tree that PR produces, ⛔ not of main today — filed now rather than lost, in the same shape #17561 was.

The declared contract, quoted

packages/spec/src/data/analytics.zod.ts states the rule in its own prose:

the refusal is shared by the schema door (this file) and, through the ANALYTICS_DATE_RANGE_UNRECOGNIZED envelope, by the runtime door and the drivers (#16322), so one condition keeps one wording (the #5240 convention)

What violates it

packages/services/service-analytics/src/date-range-array-arm.ts overwrites err.message with a second wording for the same condition. Its own comment justifies that, and the justification is specific:

the shared wording judges a bare STRING against the preset vocabulary and ends with "Refused at the schema", and neither is true of an array refused past the schema door by a face

That was correct when written. PR #18230 removes both halves of it: analyticsDateRangeRefusalMessage gains a required origin parameter, so analyticsDateRangeRefusalMessage(dateRange, 'runtime') now produces a sentence that is true for exactly that origin — an array, refused past the schema door, by a face.

⇒ after #18230, the second wording remains with no remaining reason, and the #5240 one-condition-one-wording convention is violated by a file whose only defence has been removed.

The second half — same file, same edit

The same file's header now states two things that are false of the tree #18230 produces:

  1. that AnalyticsDateRangeSchema's array arm is 「a bare z.array(z.string()) with no length constraint」 — after fix(spec)!: the dateRange array arm is exactly two string bounds, and each refusal origin gets a true sentence #18230 it is z.tuple([z.string(), z.string()]);
  2. that 「Tightening AnalyticsDateRangeSchema itself is packages/spec's call and is deliberately NOT done here」 — it has since been done, by ruling A (AnalyticsDateRangeSchema's array arm admits shapes every consumer now refuses, and the one shared refusal sentence is false for them #17598, decision batch 🔗 Broken links detected in documentation #117 item 3).

Both are prose in the same file as the overwrite. The reporting round's judgement, which this card carries forward: they are one edit, not two cards.

Class

(b) violates a declared contract, with the contract quoted from the tree rather than paraphrased. ⛔ Not (a): nothing is unreachable or crashing — a caller gets a refusal either way, just a second wording for a condition the spec says keeps one.

Measured landing point, as evidence and ⛔ not as a routing decision

packages/services/service-analytics/src/date-range-array-arm.ts. The contract it answers to lives in packages/spec/src/data/analytics.zod.ts, which is why the finding was visible from the spec lane at all.

Falsify first

⚠️ Whoever takes this re-measures against origin/main after #18230 lands, ⛔ not against this card's text:

  • does date-range-array-arm.ts still overwrite err.message?
  • does analyticsDateRangeRefusalMessage take an origin and produce a true sentence for 'runtime'?

If #18230 landed differently, this card's premise is gone and the honest answer is to close it, ⛔ not to fix something to match this description.

Dedupe words

analytics dateRange refusal wording · duplicate · service-analytics overwrite · #5240 · ANALYTICS_DATE_RANGE_UNRECOGNIZED


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions