Skip to content

spec(dashboard): a globalFilters entry named dateRange parses and silently replaces the built-in date range's binding #29213

Closed

Description

@objectstack-fleet

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Filing gate: ① a defect named out of scope by the #29023 implementer (os-dev-report 6572629846, out_of_scope_findings[0]). ⛔ Not a claim. No grade: triage sets it. Reach is NOT MEASURED at a public door: the parse accepts it, and lint's dashboardFilterDefs lets the later definition win.

What happens

Wanted

Measure it at the save door and on the console board first. If it reproduces, refuse a globalFilters entry keyed dateRange (by name, or by field when unnamed) on a dashboard that declares dateRange, naming the reserved word. That is a narrowing on the same predicate module as #29023 (packages/spec/src/ui/duplicate-global-filter-names.ts, after PR #29162 merges). Also read whether a dateRange entry is meaningful at all when the dashboard does NOT declare dateRange.

Reader who acts: domain:spec.

Dedupe: searched reserved dateRange global filter name, globalFilters dateRange collision, dashboard reserved filter name. Only #29023 and its PR. New.

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p2 · domain:spec · pm:queue (from finding) · 2026-11-02T09:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut

    Claim: PM loop round 1 · 2026-11-02T12:04Z
    Session: session_01ADHkmSduNGC2SZXszyrNut (seat); dev = card thread session_01ADHkmNvZN4TxxGwnpRp9yG
    Account: os-steve
    Branch: claude/project-thread-0uv3au
    Worktree: the card thread's own checkout of objectstack-ai/objectstack
    Domain: domain:spec
    Seat: domain:spec#2
    File surface: packages/spec/src/ui/duplicate-global-filter-names.ts (or a sibling predicate module beside it) and packages/spec/src/ui/dashboard.zod.ts (the #29162 refine attach site and the dateRange describes), their tests, the dropped-refinements baseline if the build names it, regenerated references, root .changeset/; the ADR-0087 semantic migration entry the registered changeset needs (packages/spec/src/migrations/entries/semantic/18.ui-dashboard-global-filter-reserved-date-range-refused.ts) and one sentence in content/docs/ui/dashboards.mdx (amended on the dev's report: both follow the refusal); the new object-level check exported in the file's check* idiom and re-attached on objectui's mirror ui/packages/types/src/zod/complex.zod.ts DashboardComponentSchema with its census row in ui/packages/types/src/__tests__/spec-object-refinements-7715.test.ts and its IMPORTED / REFINEMENT_EXCEPTIONS rows in ui/packages/types/src/__tests__/imported-defaults-8317.test.ts (amended on the seat's CI reading at 0aa87c6c: Test UI (6/16) counts 1 object-level check on DashboardSchema where the site names 0, the objectui#7715 parity census); ⛔ not packages/spec/src/conversions/refused-shapes.ts or packages/metadata-protocol (sibling #29212) (stop on breach; explain in the report)
    Container & model: S–M, mode:thread, model: default — the tier is the PM's per-card call (floor sonnet · default opus · ceiling fable); a narrowing of a published schema, one CONTRACT_REVIEW_TIER review by the seat before the queue, effort: high
    Clause-②: no (narrowing)
    Metadata-protocol: narrowed
    Added export (amended on the dev's report): checkDashboardReservedDateRangeGlobalFilters is the narrowing's own check made re-attachable by objectui's mirror; it widens no accept set, so the Clause-② line stands unless the changeset gate reads otherwise.
    Responsibility: packages/spec dashboard.zod.ts accepts a globalFilters entry keyed dateRange beside a declared dateRange | none: #29162's duplicate-key refusal does not cover the reserved built-in key | any dashboard author; reach at the save door and console board is measured first by the dev
    Thread-read: 6574201278
    Premise: holds (on origin/main after 38a278b7, duplicate-global-filter-names.ts says dateRange "is a different question and is not" judged there; no refusal for a dateRange-keyed entry exists); the dev measures reproduction first and stops with premise_still_valid: false if it does not reproduce
    Serial constraints cleared: #29162 (seat 1, same predicate module) merged as 38a278b7; sibling #29212 (this seat, parallel) holds refused-shapes.ts and a packages/metadata-protocol test file, disjoint from this surface

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-steve · session_01ADHkmNvZN4TxxGwnpRp9yG
    os-dev-report

    {
      "issue": 29213,
      "status": "done",
      "branch": "claude/project-thread-0uv3au",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29370",
      "head": "6d7e2382",
      "session": "session_01ADHkmNvZN4TxxGwnpRp9yG",
      "premise_still_valid": true,
      "summary": "Reproduced on main 5a2bdf9c at all three doors: DashboardSchema parses a declared dateRange beside a globalFilters entry keyed dateRange; the save door (saveMetaItem) stores it in draft (publish then succeeds) and in publish; the console's resolveDashboardFilterDefs returns one def {name:dateRange, field:region, type:text} with only a console warning, so the date-range control disappears and filterBindings.dateRange binds the entry. Now refused at every parse door: reservedDateRangeGlobalFilters joins duplicateGlobalFilterNames in duplicate-global-filter-names.ts (same class: a second definition behind one key, the built-in being the first), attached to the dashboard object because it reads the sibling dateRange, one issue per entry at globalFilters[i].name (or .field when unnamed). After: save door 422 INVALID_METADATA in draft and publish, nothing stored; a stored row still loads with _diagnostics.valid false. An entry keyed dateRange on a dashboard WITHOUT dateRange is meaningful (console draws it, filterBindings.dateRange and lint bind it, verify skips the board) and stays accepted; see open_questions. Blast radius: 0 authored dashboards carry the shape.",
      "tests": "head 6d7e2382. spec test: Test Files 792 passed (792), Tests 23402 passed | 1 todo. spec typecheck exit 0. lint test: 189/189 files, 7830 passed. metadata-protocol test: 301 passed | 4 skipped files, 22127 passed | 26 skipped. ui (from ui/) vitest packages/core/src/utils packages/plugin-dashboard: 311/311 files, 3865 passed | 6 skipped. New file dashboard-global-filter-reserved-date-range.test.ts 11/11 green. Ablation via scripts/ablation-replace.mjs on the committed fix (anchor '}).superRefine(refuseReservedDateRangeGlobalFilters));' to '}));', anchor 1 to 0, blob 74ffa70c to 080c7bf7): 5 failed | 6 passed (the five refusal cases red, controls and predicate cases green); restored blob == HEAD, git diff HEAD empty. Spec tests import ./dashboard.zod from source, so no dist leg. Save-door and console probes were scratch tests, run before and after, then deleted.",
      "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 6d7e2382: 106 families from 8 paths. All 106 run after the last commit with exit codes; --ran: 106 derived, 106 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. check-plugin-teardown-shape --self-test first exit 3 (pinned commit missing from shallow clone), exit 0 after git fetch --depth=1 origin 621a4876. spec check:generated: 14/14 up to date after gen:docs. Offline check-changeset-no-major --base 5a2bdf9c --event (PR body): exit 0; check-partof-closing-keyword on the body: exit 0. Local-only check-dev-prereqs: exit 1, 35 ui/ workspace packages unbuilt (only ./packages/** built), a container dev-server precondition, not spec dist. CI check-runs: in_progress at report time, not waited on.",
      "dogfood_battery": "6d7e2382 · os-verify-lock: VERDICT command-exit 0 (held 27m35s) · Test Files 391 passed | 3 skipped (394) · Tests 3223 passed | 28 skipped (3251) · no failures",
      "mcp_calls": "3 — mcp__github__issue_read get_comments (#29213), mcp__github__issue_read get (#29213), mcp__github__pull_request_read get (#29370); all reads, no MCP writes",
      "api_writes": "2 — relay pr_create (PR #29370, 10406 bytes sent = stored, assignees none, no labels) and this os-dev-report comment via post-stamped.mjs; plus 2 git pushes (not REST)",
      "files_changed": [
        ".changeset/29213-dashboard-global-filter-reserved-date-range.md",
        "content/docs/references/ui/dashboard.mdx",
        "content/docs/ui/dashboards.mdx",
        "packages/spec/dropped-refinements.baseline.json",
        "packages/spec/src/migrations/entries/semantic/18.ui-dashboard-global-filter-reserved-date-range-refused.ts",
        "packages/spec/src/ui/dashboard-global-filter-reserved-date-range.test.ts",
        "packages/spec/src/ui/dashboard.zod.ts",
        "packages/spec/src/ui/duplicate-global-filter-names.ts"
      ],
      "line_budget": "331 changed lines (+315 / -16), 8 files, under the 3000 human-merge threshold; no skills/** or governed path touched",
      "deviations": [
        "Two files outside the claim's file surface: packages/spec/src/migrations/entries/semantic/18.ui-dashboard-global-filter-reserved-date-range-refused.ts (the ADR-0087 semantic entry the changeset's registered disposition needs; check-adr-0087-registration green) and content/docs/ui/dashboards.mdx (one hand-written sentence naming the refusal next to the existing 'dateRange is reserved' line). The seat may amend the claim or ask for the docs sentence to be dropped.",
        "PR body line 1-2 is the harness attribution block, Fixes #29213 is line 3 (os-dev's harness-attribution exception).",
        "The harness asked for a PR assignee/reviewer via MCP writes and a PR-activity subscription; not done, because the standing order forbids MCP writes and PR assignees and the dispatch contract overrides the subscription posture.",
        "Human Minimum item 3 (pnpm lint) left unchecked in the body: lint is CI-owned and was not run locally."
      ],
      "open_questions": [
        {
          "question": "Should a globalFilters entry keyed dateRange stay accepted on a dashboard that does NOT declare dateRange?",
          "options": [
            "A: keep it accepted (this PR). It is a working filter there: the console draws its control, filterBindings.dateRange binds it, lint accepts the key, verify skips the board. Adding dateRange later is refused loudly by this rule.",
            "B: reserve the word unconditionally (refuse the entry everywhere). Widens the refusal past the card; 0 authored dashboards affected; message and describe change, one more test."
          ],
          "recommendation": "A, because the entry is meaningful without a declared dateRange and the collision this card names cannot happen there; B is a separate contract call."
        },
        {
          "question": "Predicate placement: extended duplicate-global-filter-names.ts instead of a sibling module. OK?",
          "options": [
            "A: keep it in the same module (same defect class, shares filterKeyOf).",
            "B: split into reserved-global-filter-names.ts."
          ],
          "recommendation": "A, because the built-in date range is the first declaration under the key and one module then answers every same-key collision."
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: none (note) · reach: n/a · the v18 stored-row listing packages/spec/src/conversions/refused-shapes.ts does not list this refusal; if the stored-row detector should name it, it belongs there · carrier: #29212"
      ]
    }

    Stamped 2026-11-02T13:19Z.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut

    Landed: PR #29370, merged as c268b72b at 2026-11-02T18:19Z.
    ACCEPT → PR #29370 comment 6580087029 · contract review PASS 6578522383 (6d7e2382), delta PASS 6578639267 (0aa87c6c) and delta PASS 6580064165 (6b7710c9) · name kept by the seat 6583246624.
    Follow-ups filed: #29382 (lint rule explanation's dateRange sentence), #29284 (ui mirror drops the duplicate-name refine), and the stored-row detector for this refusal (card filed next, linked below).

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions