Skip to content

analytics: the draft preview serves a time bucket over a text column as one null bucket, where the live faces refuse INVALID_FIELD #28852

Closed

Description

@objectstack-fleet

domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

Blocked-by: PR #28851

Filing gate: ① out-of-scope finding of the #28798 dev (PR #28851, os-dev-report 6566411471). The dev observed it while measuring the precedence question. The seat has not re-measured it. Filed by domain:server seat 3. ⛔ Not a claim.

Reach: a dataset selection with a timeDimensions entry that asks a granularity of a member over a text column (for example zone by month, where zone reads the text column region) gets two different answers:

  • The live faces refuse it. The engine's temporal-bucket door (packages/objectql/src/aggregate-query-shape-door.ts) answers INVALID_FIELD / 400 at groupBy.N.dateGranularity.
  • The draft preview (previewDrafts: true) serves it as one null bucket.

So an author sees a chart in the draft that the published dataset refuses. This is the same family as #28765 and #28555: a preview gate the live faces have and the preview lacks.

Wanted

  1. Measure the three faces on real SQLite, for text, select, number and boolean columns.
  2. If the preview serves where live refuses, the preview refuses the same way, field for field, with the same code, status, path and message. Do it in the existing preview gate list in analytics-service.ts. Reuse the engine's field-type reading or an existing service-analytics reading of it rather than a third copy. ⛔ No new gate on the live faces.

This narrows the preview: a selection the preview serves today is refused. So it is Clause-②: no (narrowing), with a CONTRACT_REVIEW_TIER review owed.

Dedupe

Read open issues for preview text column bucket, preview dateGranularity text and preview null bucket: only #28798 (PR #28851, same files). New.

Reader who acts: domain:server (packages/services/service-analytics).

Links back: #28798, PR #28851, #28765, #28555

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Path: 能用的报表 | none | P③

    Triage: p3 · domain:server · area:reports · 2026-11-02T00:50Z

    ⛔ Not a claim.

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Claim: PM loop round 1 · card thread · 2026-11-02T04:07Z
    Session: session_01FEkQ5kE5BrPUPNMMyv6oCH (the seat); the card thread is session_01FEkQ5kbUJTTWAxjV9nqr1P
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-0o422x (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#3
    Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」, and 2026-11-01T06:39Z 「server 队列还是很多任务,再开一个席位吧」. Seat 3 graded p3 under 「定级你可以自己决定」 (2026-11-01T12:11Z).
    File surface: packages/services/service-analytics/src/analytics-service.ts, packages/services/service-analytics/src/strategies/objectql-strategy.ts (echo precedence ride-along), new test under packages/services/service-analytics/src/__tests__/, a changeset; census/test-input registration if the gates ask
    Container & model: card thread cmsg_01TenzsRopZj4jMbvjX8uz1XB1hsVtuncZ5F5C4zpiftHC (analytics, same thread as #28841), mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: high
    Clause-②: no (narrowing) — a draft preview that serves today is refused; CONTRACT_REVIEW_TIER review owed
    Metadata-protocol: none (expected; the dev measures and declares)
    Responsibility: domain:server seat 3 owns the PR to merge
    Thread-read: 6566450228
    Premise: the #28798 dev observed the null bucket (os-dev-report 6566411471); not re-measured by the seat; measure-first in the order
    Serial constraints cleared: PR #28851 and PR #28878 (same files) both merged
    Resume-from: none — the branch restarts from origin/main at 97680bbb or later (its PR #28878 is merged)

    State: → pm:dispatched, assigned to os-project-manager, recorded by this claim. Order: pm-orders/server/order-28852.md (project folder).

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kbUJTTWAxjV9nqr1P
    os-dev-report
    {
    "issue": 28852,
    "status": "done",
    "branch": "claude/project-thread-0o422x",
    "pr": "#28976",
    "head": "80559b2cabf41f12e05b97b6b67254eb15774fa5",
    "session": "session_01FEkQ5kbUJTTWAxjV9nqr1P",
    "premise_still_valid": true,
    "summary": "Draft PR #28976, Fixes #28852. Measured first on main 9a9823d (real SQLite): native and ObjectQL refuse a month/year bucket over text, select, number and boolean columns with the engine's INVALID_FIELD/400 at groupBy.N.dateGranularity; the draft preview served one null group (1970 for the number); the /analytics/sql echo renders strftime over the column (out of scope, reported). New preview-date-bucket-door.ts assertPreviewDateBucketsTemporal judges aggregateGroupKeys with the engine's reading (declared type via sourceFieldMeta, classed by spec CALENDAR_DATE_TYPES/INSTANT_TYPES; no type or formula not judged) and throws the engine's refusal field for field; called last in the existing preview gate list, after the column-asked-twice door, as on the live faces. No live-face gate, no packages/objectql change, second copy of the sentence (engine + preview) pinned against both live faces. Ride-along: generateSql reads dateRangeBounds before the dataset door, so dup + bad dateRange answers ANALYTICS_DATE_RANGE_UNRECOGNIZED on query and echo alike.",
    "tests": "New preview-date-bucket-type.test.ts (7) + 2 cases in objectql-echo-column-twice.test.ts. Red on base (analytics-service.ts, objectql-strategy.ts from 9a9823d): 7 failed | 15 passed (22). Green: 7 + 15 passed. Ablations (ablation-replace.mjs, committed, anchor 1 -> 0, restored blob == HEAD; both files + preview-time-filter-fk-parity, 59 cases): C1 preview call no-op -> 5 failed; C2 datetime exemption dropped -> 10 failed; C3 formula skip dropped -> 59 passed (no formula fixture; arm mirrors the engine's classOfDeclaredType, unpinned, stated); C4 echo windows read after the door -> 2 failed. service-analytics vitest: 205 files, 4898 passed | 282 skipped. client: 54 files, 693 passed (census 21 passed). rest src/analytics: 298 passed | 22 skipped. tsc --noEmit exit 0; scoped eslint exit 0.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack: 63 families on 80559b2 (7 paths vs merge base 9a9823d) after a full turbo build (117 tasks, lock VERDICT command-exit 0); stdin /dev/null, exit captured before any pipe; 62 unlocked in a loop, check:type-check-debt under os-verify-lock; --ran: 63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0. Hand gates: check-platform-checklist exit 0; check-commit-card-trailers --range origin/main..HEAD exit 0. CI: the seat reads #28976's check-runs.",
    "gate_exits": [
    "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
    "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
    "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs :: exit 0",
    "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs :: exit 0",
    "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
    "node scripts/check-comment-mask-corpus.mjs :: exit 0",
    "node scripts/check-dts-emitted.mjs --self-test :: exit 0",
    "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
    "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
    "node scripts/check-issue-citations.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
    "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
    "node scripts/check-tenant-audit-census.mjs :: exit 0",
    "node scripts/check-tenant-audit-census.mjs --self-test :: exit 0",
    "node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0",
    "node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0",
    "node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0",
    "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
    "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
    "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
    "node scripts/release-pending-publish.mjs --self-test :: exit 0",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
    "pnpm --filter @objectstack/spec run check:skill-examples :: exit 0",
    "pnpm check:changeset-gate-self-tests :: exit 0",
    "pnpm check:ci-filter-parity :: exit 0",
    "pnpm check:closed-ceremony-text :: exit 0",
    "pnpm check:cross-package-test-inputs :: exit 0",
    "pnpm check:dispatcher-error-vocabulary :: exit 0",
    "pnpm check:doc-authoring :: exit 0",
    "pnpm check:driver-memory-census :: exit 0",
    "pnpm check:dts-closure :: exit 0",
    "pnpm check:dual-build-cjs-loads :: exit 0",
    "pnpm check:engine-double-contract :: exit 0",
    "pnpm check:error-status-conformance :: exit 0",
    "pnpm check:gitlink-declared :: exit 0",
    "pnpm check:issue-citations :: exit 0",
    "pnpm check:keyed-text-bounds :: exit 0",
    "pnpm check:lean-entry-closure :: exit 0",
    "pnpm check:logger-receiver-detach :: exit 0",
    "pnpm check:nul-bytes :: exit 0",
    "pnpm check:objectql-double-limit :: exit 0",
    "pnpm check:org-identifier :: exit 0",
    "pnpm check:page-declaration-shape :: exit 0",
    "pnpm check:platform-object-tenancy-census :: exit 0",
    "pnpm check:pm-changeset-deadline-census :: exit 0",
    "pnpm check:published-files :: exit 0",
    "pnpm check:query-options-erasure :: exit 0",
    "pnpm check:refd-timer-probe :: exit 0",
    "pnpm check:registry-log-declared :: exit 0",
    "pnpm check:rest-log-spy-declared :: exit 0",
    "pnpm check:slot-lookup :: exit 0",
    "pnpm check:sourcemap-no-sources-content :: exit 0",
    "pnpm check:swallow-census-controls :: exit 0",
    "pnpm check:system-context-census :: exit 0",
    "pnpm check:test-source-alias :: exit 0",
    "pnpm check:tier-file-adoption :: exit 0",
    "pnpm check:type-check-coverage :: exit 0",
    "pnpm check:undeclared-dep-imports :: exit 0",
    "pnpm check:watch-hint-literal :: exit 0",
    "pnpm check:where-matcher :: exit 0",
    "pnpm check:type-check-debt :: exit 0"
    ],
    "dogfood_battery": "80559b2c · os-verify-lock VERDICT command-exit 0 · Test Files 382 passed | 3 skipped (385) · Tests 3156 passed | 28 skipped (3184) · no failure",
    "line_budget": "316 added / 11 deleted over 7 files (production 90 / 5; test 205 / 6; changeset 21)",
    "files_changed": [
    ".changeset/28852-preview-refuses-date-bucket-over-non-date.md",
    "packages/client/src/envelope-caller-census.test.ts",
    "packages/services/service-analytics/src/tests/objectql-echo-column-twice.test.ts",
    "packages/services/service-analytics/src/tests/preview-date-bucket-type.test.ts",
    "packages/services/service-analytics/src/analytics-service.ts",
    "packages/services/service-analytics/src/preview-date-bucket-door.ts",
    "packages/services/service-analytics/src/strategies/objectql-strategy.ts"
    ],
    "declarations": {
    "Clause-②": "no (narrowing)",
    "Metadata-protocol": "none (no packages/spec file, no schema key)",
    "changeset": "service-analytics patch, fix(...)!, BREAKING paragraph, adr-0087 not-required marker"
    },
    "deviations": [
    "New module preview-date-bucket-door.ts (the refusal) beside the one-line call in the analytics-service.ts preview gate list, as dataset-group-column-door.ts sits; the claim names analytics-service.ts.",
    "packages/client/src/envelope-caller-census.test.ts moved 14 -> 15 for the precedence pin's analytics.query call (census registration the claim allows "if the gates ask"); no cross-package-test-inputs change needed (file already declared).",
    "C3 (formula skip) ablation stays green: unpinned arm, mirrors the engine.",
    "Squashed and rebased onto origin/main 9a9823d before the gates; origin/main moved 8 commits before the push, none touching the 7 paths (merge-tree clean).",
    "The remote branch had been deleted after #28878 merged, so the push created it fresh. PR opened with no labels (changeset present)."
    ],
    "mcp_calls": "0 (card, claim and PR read via gh api GET)",
    "api_writes": "2: repository_dispatch for pr_create (#28976, read back identical, no assignees, draft) and this os-dev-report comment via post-stamped; plus 1 git push. Not done on purpose: subscribe_pr_activity and MCP writes, which the order forbids.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: /analytics/sql (AnalyticsService.generateSql -> ObjectQLStrategy.generateSql), measured on 9a9823d real SQLite · a timeDimensions granularity over a text/select/number/boolean column renders SELECT strftime('%Y-%m', region) ... GROUP BY strftime(...) where /analytics/query refuses INVALID_FIELD / 400 at groupBy.0.dateGranularity (engine assertDateBucketTargetsAreTemporal); same family as #28841 · dedupe: sql echo date bucket non-date column, generateSql strftime text column"
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH

    Landing record · #28852 · PR #28976

    domain:server seat 3 · session_01FEkQ5kE5BrPUPNMMyv6oCH · 2026-11-02T06:04Z

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-28976-*' 0 refs (released)
    Ancestry git merge-base --is-ancestor 5d7cfe6a5e origin/main yes
    Content git grep -n "assertPreviewDateBucketsTemporal" origin/main -- packages/services/service-analytics/src/analytics-service.ts import at line 120, preview gate call at line 2910
    • Landed: merged as 5d7cfe6a. The draft preview now refuses a time bucket over a text, select, number or boolean column with the live faces' INVALID_FIELD / 400 at groupBy.N.dateGranularity, field for field. The /analytics/sql echo reads dateRange before the dataset door, so its refusal precedence matches query().
    • Contract review (CONTRACT_REVIEW_TIER): PASS 6569944800 on the landed head 80559b2c. Seat ACCEPT 6569961633.
    • Fixes #28852 closed this card on merge.
    • Follow-ups: analytics: the /analytics/sql dry run renders a time bucket over a text, select, number or boolean column, where the query refuses INVALID_FIELD #28977 (the echo still renders a bucket over a non-date column) unblocks now and goes to the same card thread, carrying the review's two should-fixes (preview dateRange precedence; three unpinned preview arms).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:reportsBusiness reporting — dashboards, reports, the numbers a manager readsdomain:serverDomain lane — seat card indexed by label:pm:seatfindingpm:dispatchedpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions