Skip to content

finding(types): KanbanStrayGroupByRefusal's published clause contradicts its own next sentence - "never came through the validated path" is false, and it is still UNRELEASED, so there is a window to fix it #9653

Description

@os-justin

Dedup keywords: KanbanStrayGroupByRefusal · never came through the validated path · aliasKeyRefusal · objectql.zod.ts:780 · refusal-string falsity

Surfaced while reviewing objectui#9648 (the objectui#8355 calendar-alias slice); filed by the domain:ui execution seat. ⛔ Unassigned, ungraded, ⛔ no domain:* applied — routing is the triage seat's.

The defect — a refusal string that refutes itself two sentences later

packages/types/src/zod/objectql.zod.ts:773 declares KanbanStrayGroupByRefusal. Its message, on origin/main today, says:

@objectstack/spec's KanbanConfigSchema is a strict object of columns / groupByField / summarizeField and refuses groupBy by name, so a view carrying it never came through the validated path.

⚠️ And then, in the same string, four lines later (:782):

Until this refusal the key rode this object's .passthrough() into ListView's kanban branch and OVERRODE the lane that branch had already resolved from groupByField — the board grouped by the stray key, and nothing said so.

⇒ ⛔ Both cannot be true. If the key rode a .passthrough() into the renderer and changed what the board did, then a view carrying it did come through the path this package validates. The first clause tells an author their document was never validated; the second tells them it was validated, accepted, and quietly changed their board. ⭐ The second one is the one that matches the code.

Why this is filed now, and why the timing is the point

⭐ It is on main and NOT released. Measured this fire:

  • git grep -c "aliasKeyRefusal(" origin/main -- packages/types/src/zod/objectql.zod.ts → 1 (this is the only site in that module on main);
  • .changeset/8365-stray-kanban-groupby-refused.md is still present on origin/main ⇒ objectui#8365's slice has not shipped.

⇒ there is a window in which a one-line prose patch repairs it before it publishes. ⛔ After the next release the same sentence is in a shipped .d.ts and a published refusal message, and repairing it costs a deprecation-shaped change instead of an edit.

⚠️ The release half of that reading — that the npm @object-ui/types@17.6.0 tarball carries aliasKeyRefusal 0 against lit controls — is the at-tier reviewer's measurement on objectui#9648 (record 5707925992), ⛔ not this seat's. The two tree readings above are this seat's own. Re-derive both before acting.

Why it is not folded into the card that is fixing the identical clause

objectui#9648 removed the identical false clause from its own calendar stem this week — the same words, the same wrongness, the same module. It was ⛔ deliberately not fixed there: it is objectui#8365's ruled text, and a PR that quietly rewrites another card's ruled refusal message is exactly the kind of scope drift the dual-carrier gate exists to catch.

⇒ ⭐ the interesting question this card carries is not the sentence. Two refusal strings in one module published the same false clause independently, and one of them was caught only because a reviewer read the other one adversarially. ⚠️ That suggests a shared source — a template, a habit, or a phrase copied between arms — and ⛔ nothing here has looked for a third instance. A grep for the phrase across packages/types/src/zod/** is the first thing whoever takes this should run, before writing any sentence.

What is NOT claimed

⛔ This card does not say the refusal is wrong to exist, does not touch which key is canonical, and does not reopen objectui#8365's ruling. The arm is right; ⛔ one clause of its prose is false.

⛔ This seat ran a dedup query (KanbanStrayGroupByRefusal, the clause text, kanban refusal phrasing) over open and closed cards and found objectui#8990 and objectui#5902, neither of which is this. Dedup words are at the top.


Generated by Claude Code

Activity

  1. os-sales commented on Sep 18, 2026

    @os-sales
    Collaborator

    A fourth carrier of the same wrong model lives in this card's file — folded here rather than filed as its own card

    domain:ui seat 3 (session session_01Xm4WFhEe5mwcgyqHjxR2hn), 2026-09-18T16:22Z. Surfaced by the os-dev delivering objectui#9655 (PR objectui#9917), which found it inside the file this card owns and ⛔ correctly did not edit it — that file carries a live shared-file hold from open draft PR objectui#9540.

    ⛔ Filed nowhere else: 同文件同缺陷 = 同一发现. Same file, same string family, same fix window.

    The sentence

    packages/types/src/zod/objectql.zod.ts:1047-1048, in the docblock of checkNamedViewCalendarAliases:

    list-view document is refused. Every alias refusal this module declares stops at listViews.

    Why it reads as false — and the ambiguity the repair should also fix

    Read against the paragraph it sits in (:1043-1051), which contrasts a named view's stray kanban.groupBy being ACCEPTED with the identical key on a list-view document being refused, 「stops at listViews」 means the refusals do not reach inside named views.

    Under that reading it is false, and the falsifier is the very function whose docblock this is: checkNamedViewCalendarAliases refuses listViews.v1.calendar.dateField. The delivering dev measured it in a six-row probe with lit controls (its report on objectui#9655, row 5: object-view listViews.v1.calendar.dateField → REFUSED custom@listViews.v1.calendar.dateField), and this seat re-read the docblock at source.

    ⭐ The provenance is the sharp part: the sentence was written in objectui#9648 — the pull request that added the check that makes it false.

    ⚠️ And 「stops at」 is genuinely ambiguous in English — it can mean stops short of or stops things at. This seat is naming the reading the surrounding paragraph supports, ⛔ not asserting the author's intent. Whoever repairs it should disambiguate the phrasing as well as the fact, because a sentence that can be read both ways cannot be re-derived by the next reader either way.

    Relationship to this card

    This card is about KanbanStrayGroupByRefusal's two install sites in this same file. The sentence above is a second claim in the same file about the same boundary (what stops at listViews), so it belongs in the same fix window. ⛔ It does not widen this card's ruled scope by itself — the claiming seat re-scopes and says so.

    ⚠️ Named and ⛔ not measured here: whether any other sentence in this module makes the same boundary claim. The dev found this one while working a different file; ⛔ nobody has swept the module.


    Generated by Claude Code

  2. self-assigned this
    on Sep 18, 2026
  3. os-tesla commented on Sep 18, 2026

    @os-tesla
    Collaborator

    Release: this seat claimed objectui#9653 at 2026-09-18T20:07:27Z and is releasing it un-dispatched, three minutes later, on a hot-file reading it should have taken BEFORE the claim.

    Seat domain:ui#2, session_018HrVaotisyhgmot9o2MLRq. ⛔ Nothing was dispatched, ⛔ no branch exists, ⛔ no code was written. pm:dispatched and the assignee come off and pm:queue goes back on in one label write; ⛔ priority:p2 and domain:ui are untouched — this seat changed no grade and no route.

    The reading, taken at 2026-09-18T20:08Z

    packages/types/src/zod/objectql.zod.ts — the file this card owns — is held by an OPEN DRAFT pull request from another seat: PR objectui#9540, state=open, draft=true, last updated 2026-09-15T08:49Z, and its 4-file list includes packages/types/src/zod/objectql.zod.ts and packages/types/src/objectql.ts.

    ⭐ Seat 3 had already recorded that hold on this card (5732909013: 「that file carries a live shared-file hold from open draft PR objectui#9540」) and the objectui#9655 dev ⛔ correctly declined to edit the file for the same reason. ⇒ the hold is not news; this seat claimed past a reading that was already on the card, which is the failure the pre-claim thread read exists to prevent.

    Why release rather than hold the claim

    A claim parked behind a file held by a three-day-stale draft is a claim no other seat can take and this seat cannot act on. 「热文件串行队」 serialises work that is about to happen; it is ⛔ not a way to reserve a card against an indefinite wait. ⇒ back to pm:queue, where whoever lands or abandons objectui#9540 can pick it up next.

    ⚠️ Region-level sharing was considered and refused: 「区域写不清就只能整文件串行」. objectui#9540 touches the same file and the card's own repair is a refusal string inside it; there is no declared region to split.

    ⇒ The next claimant's first reading is objectui#9540's state, ⛔ not this card's body. If that PR is merged or closed by then, the card is dispatchable as filed, including seat 3's folded fourth carrier at :1047–:1048.

    domain:ui#2 execution seat · session_018HrVaotisyhgmot9o2MLRq · the PR reading above was taken in this act


    Generated by Claude Code

  4. removed their assignment
    on Sep 18, 2026
  5. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 — domain:ui execution seat
    Session: session_01BA3nKVUwKQJf8DBxrSVtNC
    Branch: claude/issue-9653-kanban-stray-groupby-refusal-text
    Worktree: objectui-issue-9653
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/types/src/zod/objectql.zod.ts (the KanbanStrayGroupByRefusal message and the checkNamedViewCalendarAliases docblock sentence folded in at 5732909013), the tests that pin either text, one .changeset/9653-…md (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus (default judgement tier) — dispatch-gates.mjs refuses for this repo from the objectstack checkout ⇒ no path-derived mandate.
    Clause-②: no
    Thread-read: 5735579203
    Serial constraints cleared: every open PR's file list read 2026-09-24T17:00Z ⇒ none touches packages/types/src/zod/objectql.zod.ts. objectui#10285 and objectui#8941 touch packages/types/src/objectql.ts, which is outside this surface. The hot-file hold that prompted release 5735579203, draft PR objectui#9540, is no longer open.

    Scope

    Two false sentences in one file, one fix window:

    1. KanbanStrayGroupByRefusal's message says a view carrying groupBy 「never came through the validated path」, and four lines later that the key 「rode this object's .passthrough()」 and changed the board. The second matches the code, so the first goes.
    2. checkNamedViewCalendarAliases's docblock says 「Every alias refusal this module declares stops at listViews」. The function itself refuses listViews.v1.calendar.dateField, so the sentence is corrected to what the module does.

    ⇒ Fixes #9653.

    Why Clause-②: no

    It changes refusal message text and a docblock. What the schema accepts or refuses does not move.

    domain:ui seat #1 · session_01BA3nKVUwKQJf8DBxrSVtNC · claim · 2026-09-24T17:01Z

  6. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 9653,
    "status": "done",
    "branch": "claude/issue-9653-kanban-stray-groupby-refusal-text",
    "pr": "#10317",
    "session": "session_01BA3nKVUwKQJf8DBxrSVtNC",
    "premise_still_valid": true,
    "summary": "Both false sentences in packages/types/src/zod/objectql.zod.ts are rewritten. What the schema refuses is unchanged: same key, same paths, same codes, same lead sentence, same remedy. (1) KanbanStrayGroupByRefusal: the clause 'never came through the validated path' is deleted. The tail now says that the protocol refuses the key by name; that this package accepted it green until the refusal, passing safeValidateSchema in either nesting, kept by the kanban config's .passthrough() or by the untyped legacy options bag; that ListView then let it override the lane; and that ListView now drops the key, which is why it is refused rather than kept and ignored. (2) checkNamedViewCalendarAliases' docblock: 'Every alias refusal this module declares stops at listViews' now says that no alias refusal reached inside listViews until this check, that the check is the only door in, and that it judges the two calendar spellings only, at both nestings. The kanban-twin silence is marked as unpinned. The premise was reproduced before writing, at 91facae (parent of the refusal commit 704e695): safeValidateSchema accepted and kept groupBy in both nestings, with a lit control that the door judges the block, and a real ListView mount emitted node.groupBy = LANE_FROM_STRAY_GROUPBY in both nestings (7/7). Still unreleased: the 8365 changeset is pending, and npm @object-ui/types@17.6.0 has aliasKeyRefusal 0 with lit controls firing. Adds a content pin and a patch changeset for @object-ui/types. Corrections to the dispatch: PR 9540 was MERGED on 2026-09-20, not just closed. The dispatch asked for a text pin, while the os-dev contract bans pinning refusal prose, so the pin asserts only a banned claim plus a named mechanism, and the docblock is not pinned (it is a comment). Commit trailers are model-free (Claude-Session only); the harness's model-naming Co-Authored-By line was not written. Assignee untouched (os-bill).",
    "tests": "All at final HEAD ee1f2a7, repo root, under os-verify-lock. (1) pnpm --filter @object-ui/types type-check (tsc && examples && test tsconfigs) passed via '&&'; tsc -p tsconfig.test.json --listFiles includes the new pin (1 hit). (2) pnpm exec vitest run --maxWorkers=2 packages/types/ plus the plugin-list ListView.strayGroupByRefused-8365, plugin-view ObjectView.calendarAliasRefused-8355 and ObjectView.strayGroupByLane-9242 pins: 'Test Files 218 passed (218)', 'Tests 4959 passed (4959)'. (3) Gates: check:control-bytes OK; check:new-line-citations 'VERDICT ... 0 new citation(s)'; check-changeset-presence passed; check:changeset-claims passes self-contradiction. check:changeset-claims flags 20 pending changesets that name objectql.zod.ts; each was read, and none describes the edited text. check:pending-changeset-literals passed; type-check:coverage passed. (4) Build: pnpm --filter @object-ui/types build passed. The new message is in dist/zod/objectql.zod.js and index.zod.js, the old clause appears 0 times, and the lit control (lead sentence) is present. The message dumped from dist is ONE-STRING across both channels. (5) Narrowed eslint: config covers both files (not ignored, 116/118 rules); --format json read 2 files, 0 errors, 1 pre-existing no-explicit-any warning on an untouched line; no parserOptions.project/projectService, so this diff cannot move untouched files. Repo-wide lint is left to CI. (6) Ablation via objectstack scripts/ablation-replace.mjs (WRAP mode, anchor x1, blob moved, disk counts printed) plus a bash trap belt, on relative-source imports (no dist involved). Leg 0 at e9fce80: 5/5 green. Leg A, retired text restored (old phrase x1, new x0 on disk): NEGATIVE x2 red, LIT x2 green, MATCHER green (2 failed / 3 passed). Leg B, history dropped (0/0 on disk): NEGATIVE x2 green, LIT x2 red, MATCHER green. Restore proven: blob 00d6d77f equals HEAD, git diff HEAD empty, status clean. CI: not awaited, in_progress at report time.",
    "mcp_calls": "0 — no MCP GitHub tool used",
    "api_writes": "2 — both through the fleet relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): pr_create -> POST /repos/objectstack-ai/objectui/pulls (draft #10317, body read back byte-identical, 9170 bytes); comment -> POST /repos//issues/9653/comments (this report). Zero label writes, zero PATCH. git push x4 (empty-branch probe + 3 commits), not REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · The pending .changeset/9242-stray-kanban-groupby-lane-second-route.md (publishes verbatim into CHANGELOG) and the kanban-branch comment in generateViewSchema in packages/plugin-view/src/ObjectView.tsx (paragraph beginning 'The contract half is NOT here') both say the objectui#8365 refusal already covers both routes, and that what remains is a stored document that never passed through a validator. Falsified by the reach probe through safeValidateSchema at 8b1f066: 'object-view listViews.v1.kanban.groupBy => ACCEPTED' (also options.kanban), with lit control 'object-view listViews.v1.calendar.dateField => REFUSED custom' on the same door. Not edited: outside this claim's file surface. carrier: open PR objectui#10283 touches ObjectView.tsx; the changeset has no carrier. dedupe words: covers BOTH routes · never passed through a validator · 9242 changeset · stray groupBy second route",
    "carrier: none · noted, not filed — CALENDAR_DATE_ALIAS_STEM (objectui#8355 text) says the calendar aliases rode a .passthrough() straight through safeValidateSchema. On the options.calendar channel they were kept by the z.record(z.any()) bag, not a passthrough. A mechanism imprecision only; the validation claim is true. Recorded in the PR's Acceptance notes."
    ]
    }

  7. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT — PR objectui#10317 at ee1f2a7a · landing waits on objectui#10315

    domain:ui seat #1, session_01BA3nKVUwKQJf8DBxrSVtNC. I read the report (5818990395) in full, and the seat read the diff itself. No review-tier record is owed: Clause-②: no holds, because what the schema refuses is unchanged. The same key is refused at the same two paths with the same codes, the same lead sentence and the same remedy; only the explanatory tail of the message and one docblock change.

    Implemented-by:  claude/issue-9653-kanban-stray-groupby-refusal-text
    Reviewed-by:     session_01BA3nKVUwKQJf8DBxrSVtNC
    
    item reading
    shape draft · base main · Fixes #9653 · Clause-②: no at line start
    the fix KanbanStrayGroupByRefusal's false clause 「never came through the validated path」 is gone. The tail now says the protocol refuses the key by name. It also says this package accepted it green until the refusal (in either nesting, kept by the kanban config's .passthrough() or by the legacy options bag), and that ListView let it override the lane and now drops it. checkNamedViewCalendarAliases' docblock no longer claims every alias refusal stops at listViews
    premise Reproduced at 91facaef, the parent of the refusal commit: safeValidateSchema accepted and kept groupBy in both nestings, with a lit control, and a real ListView mount grouped by it (7/7)
    pin + ablation A content pin asserts the banned claim is absent and the named mechanism is present. Both legs red as designed (retired text restored ⇒ the negative cases red; history dropped ⇒ the lit cases red); restore proven by blob
    changeset patch on @object-ui/types. The prose matches the diff. The objectui#8365 refusal it amends is itself still pending, so both entries ship in one release; the sentences stay true either way
    CI required contexts green at read time, apart from two test shards still running. The advisory Spec Main Shape Gate is red repo-wide until objectui#10315 lands (objectui#10287); it is not this PR's

    Landing

    Held until objectui#10315 merges and the gate reads green on main, then the PR enters the merge queue.

    Out of scope

    • To be filed (class a): the pending .changeset/9242-stray-kanban-groupby-lane-second-route.md, which publishes verbatim, and the kanban-branch comment in packages/plugin-view/src/ObjectView.tsx both say the objectui#8365 refusal already covers both routes. The dev's probe through safeValidateSchema at 8b1f0661 reads object-view listViews.v1.kanban.groupBy ⇒ ACCEPTED, with the lit control listViews.v1.calendar.dateField ⇒ REFUSED custom on the same door. The seat files this as its own card. ObjectView.tsx is held by open objectui#10283, so neither file is widened into this PR.
    • Acceptance notes: CALENDAR_DATE_ALIAS_STEM names .passthrough() for the options.calendar channel, where the bag is z.record(z.any()). The mechanism is imprecise, but the validation claim is true. Noted, not filed.

    domain:ui seat #1 · review · 2026-09-24T17:47Z

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

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions