Skip to content

fix(service): retire crm_case.created_date — cases use the platform's created_at - #2009

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-1992-case-created-at
Oct 8, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-1992-case-created-at

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #1992
Clause-②: no

This PR retires crm_case.created_date. Every reader moves to the platform-injected created_at, following ruling 5974449549 (option A, the maintainer's 「决裁的三张同意」), which was restarted by 6037965448 (「1992 重启」). It is the same change #575 B2 made on crm_opportunity. Before this PR, a case created in the UI or through REST stored created_date: null, so "Cases Opened by Priority × Day" and the service dashboard's date range left it out.

Step one: fresh-boot probe on 17.7.0, measured before any edit

The probe ran on this branch's tree at c9678036, which is origin/main with @objectstack/* 17.7.0. The installed @objectstack/objectql CHANGELOG.md:424 reads be55fd2: A seed row's authored created_at is kept when the row is first inserted … (#21646).

Method:

  1. Ran pnpm build (under os-verify-lock, VERDICT command-exit 0) and copied dist/objectstack.json into the scratchpad.
  2. Edited two crm_case seed rows in the copy only. "Data export timing out for large datasets" got created_at: { dialect: cel, source: daysAgo(5) }. "How to configure SSO with Okta?" got created_at: '2026-09-01T12:00:00.000Z'.
  3. Booted objectstack start -p 4820 --artifact COPY --home FRESH_HOME -d file:FRESH_HOME/db.sqlite from a directory with no objectstack.config.ts. The banner read "No objectstack.config.ts found — booting from artifact", and the database file did not exist before the boot.
  4. Signed up and read GET /api/v1/data/crm_case, which returned 38 rows.
seed row authored created_at read back after the first boot
Data export timing out for large datasets daysAgo(5) 2026-10-03T00:00:00.000Z
How to configure SSO with Okta? 2026-09-01T12:00:00.000Z 2026-09-01T12:00:00.000Z
Login issues after platform upgrade (control, no created_at) none 2026-10-08T02:31:17.592Z, the seed-time instant

Both authored instants were kept on the first insert, and the control row got the boot instant. Mechanism assumption 1 holds, so the retirement went ahead. Had the probe failed, the card would have stopped here.

What changed

  • case.object.ts: created_date is removed, and a comment in the Follow-up to #514: remaining behaviour fixes, conventions, and the action-sandbox test gap #575 B2 shape says why. The sla field group drops from 7 members to 6. The object has 24 fields; it had 25.
  • case.report.ts: "Cases Opened by Priority × Day" buckets on created_at. Its runtimeFilter: { created_date: { $ne: null } } is gone. That filter only ever excluded the cases nothing had stamped, and every case now carries created_at. The false comment saying "created_date is stamped by the platform" is replaced.
  • case.dataset.ts: the case_metrics day dimension is now created_at (label "Created", dateGranularity: 'day'). It has the same name and field that account_metrics and lead_metrics already use.
  • service.dashboard.ts: dateRange.field, plus the daily_case_volume filter and dimension, use created_at.
  • case.view.ts: case_timeline.startDateField is created_at, the same spelling deal_timeline uses. The create-form roster comment is updated to match.
  • case.hook.ts: the resolution-time chain reads input.created_at, then previous.created_at. created_at is stamped by sys_stamp_audit_insert at priority 10, before case_sla_defaults at priority 200; objectql sorts hooks ascending.
  • service.seed.ts: the 8 literal case rows and the 30-row generator author created_at. The celCaseSlaDue doc now reads created_at + matrix.
  • Comments: src/sales/data/_shared.ts (seed doctrine rule 1) and src/sales/data/sales.seed.ts.
  • Translations: the crm_case.created_date label is removed from all 4 objects.service.ts packs. In the case_metrics blocks of the zh-CN, es-ES and ja-JP app.ts files, the dimension key created_date is now created_at, with the labels unchanged.
  • Docs: content/docs/service/cases{,.zh-Hans,.zh-Hant}.mdx. The SLA & Priority row no longer lists Created Date. Resolution time is measured from the case's creation moment. The field count goes 25 to 24, and the Details-tab arithmetic follows (fifteen to fourteen, eight to seven).
  • docs/STATUS.md: the pnpm validate transcript reads 358 fields; it read 359. This file is outside the claim's file surface. The edit is forced by test/docs-declared-versions.test.ts, which went red on the first pnpm verify.
  • Changeset: .changeset/1992-case-created-at.md (patch, the same bump as Follow-up to #514: remaining behaviour fixes, conventions, and the action-sandbox test gap #575 B2). It is written for the release-notes reader, with a FROM → TO section.

Reader roster, re-taken by hand on c9678036

I ran git grep -c created_date and classified each hit:

  • Moved to created_at: everything listed above, plus 8 test files.
  • Left alone, belonging to the Follow-up to #514: remaining behaviour fixes, conventions, and the action-sandbox test gap #575 retirement on crm_opportunity: src/sales/objects/opportunity.object.ts, src/sales/views/opportunity.view.ts, and the opportunity half of test/opportunity-creation-date.test.ts.
  • Left alone, historical: the 7 CHANGELOG.md hits.
  • Docs: content/docs has zero created_date hits, as the earlier dev found. The case pages do name the field by its label (Created Date / 创建日期 / 建立日期) in all three locales. Those mentions are covered under Docs above.

Tests

  • New test/case-creation-date.test.ts has eight tests:
    • Static: crm_case declares no created_date; no locale pack labels it; the report column, the dashboard range and case_timeline read created_at; nothing over case_metrics, its reports, the service dashboard or the case views names created_date.
    • Executed: on a real kernel (sqlite-wasm, ObjectQLPlugin, so the platform's own audit hook does the stamping), a case inserted with no date at all is stamped and counted by the shipped report, using its rows, columns, values and runtimeFilter. It lands on today's bucket and inside the dashboard's last_7_days window. A row written in SEED_WRITE_EXECUTION_CONTEXT keeps its authored created_at and lands on its authored day.
  • Moved to created_at: dashboard-date-range-window, dashboard-agent-global-filter, dataset-granularity, docs-service-index-analytics, seed-consistency and case-create-form-narrowing. The last one loses its created_date roster entry; "ten above" becomes "nine above".
  • opportunity-creation-date: the test "crm_case keeps its own created_date" is removed, because it now asserts something false. The header comment points to the new file.
  • Range field type: action-references and dashboard-date-range-window now read a range field's type from the platform-materialised object (applySystemFields). created_at is injected and never listed in fields. Without this, the dashboard would drop out of datetimeWindowed and leave the window tests with nothing to run.

Reverse verification. The fix was committed first (HEAD 9440aec). The 16 src paths of f7b9192 were set back to c9678036 with git checkout, and the committed new test was run against them. I predicted red. It ran Tests 6 failed | 2 passed (8), exit 1. The 4 static tests failed, and both executed tests failed: "the report dropped a case: []: expected +0 to be 2" and "the last-7-days range left a case out: expected +0 to be 2". The two that stayed green are the non-vacuity check and the platform-stamp positive control. Restore: git checkout HEAD -- PATHS, then git diff HEAD was empty and all 16 blob hashes matched HEAD. The script carried a trap on EXIT/INT/TERM.

Fresh boot after the change (mechanism assumption 3)

I booted the branch's own dist/objectstack.json (built from 0e354fa, unedited) the same way on a fresh database. Then I signed up and made one REST create: POST /api/v1/data/crm_case, status 201, CASE-00039, created_at 2026-10-08T02:47:06.056Z.

  • GET /api/v1/data/crm_case returned 39 rows. Their created_at values span 31 distinct UTC days, 2026-09-08 to 2026-10-08. The only row on 2026-10-08 is the REST-created case. The three rows from step one read daysAgo(2) = 2026-10-06, daysAgo(3) = 2026-10-05 and daysAgo(5) = 2026-10-03.
  • POST /api/v1/analytics/dataset/query with case_metrics, dimensions [priority, created_at] and case_count returned 39 cells totalling 39. The REST case appears as { priority: High, created_at: 2026-10-08, case_count: 1 }.
  • With the dashboard's preset windows on created_at: last_90_days counted 39 and last_7_days counted 15.

Coupling with #2003

The case sla group now has 6 members: priority, closed_date, first_response_date, resolution_time_hours, sla_due_date, is_sla_violated. The case_detail.page.ts note #2003 added ("Not on sla: outside the strip its members are stamps no one types (closed_date and resolution_time_hours at close, first_response_date by event.hook.ts)") already names exactly the three non-strip members of the 6-member shape, so it still reads right. #2003's changeset sentence ("SLA & Priority, whose dates are recorded for you") also still holds.

Acceptance notes

  • defineSeed(Case, …) does not type-check record keys. In a trap-restored mutation, a seed key created_atx on crm_case passed tsc --noEmit (exit 0) and pnpm validate ("Validation passed", exit 0). The @objectstack/spec defineSeed doc promises "typos in record field names are caught at compile time". This is a platform-side finding, reported to the seat for upstream filing. What the runtime does with such a key is not measured.
  • Pre-existing, not touched here: the "The detail screen" section of content/docs/service/cases*.mdx still describes three authored sections ("Case Information / Status & SLA / Description", 10 fields). case_detail.page.ts has declared six { group } sections since crm_case 与 crm_lead 同病:三套互不相同的字段分组(fieldGroups 6 / 详情页 3 / 表单 3),escalated_date 三处写入、零处展示 #970. This PR only corrected the field counts and removed the retired field's mentions.
  • Pre-existing token-ratchet advisory, not acted on: "src/service interaction layer … re-anchor this ceiling to ~6,000". It reads 1,403 tokens of headroom on base and 1,405 here.

Gates

  • pnpm verify on c05b442 (git rev-parse --short HEAD printed by the same run), under os-verify-lock: VERDICT command-exit 0.
    • validate: "✓ Validation passed"
    • typecheck: exit 0
    • lint: "1 warning(s), 18 suggestion(s)". The warning is the pre-existing sales_home_page page:card one, also present on base.
    • lint:i18n-gate: "✓ i18n lint gate: 0 i18n/missing-* issues"
    • hygiene: "✓ source hygiene clean"
    • hygiene:tokens: "✓ source token ratchet clean". src/service goes from 20,549 to 20,478 authored tokens.
    • build: "✓ Build complete" with 9 author-time warnings, the same 9 as base.
    • test: "Test Files 178 passed (178)", "Tests 3803 passed | 1 skipped (3804)". The skip is the pre-existing describe.runIf(!bucketsAreHonoured) 16.x branch in dataset-granularity.
  • The first pnpm verify on 0e354fa was red in exactly one test, docs-declared-versions ("Fields: page says 359, the stack registers 358"). c05b442 updates the transcript.

Generated by Claude Code

claude added 4 commits October 8, 2026 02:36
… platform's created_at

The case object declared a readonly created_date beside the created_at the
platform injects and stamps on every insert. Nothing wrote it on a real case
(only the seeds set it), so a case created through the UI or REST stored null
and fell out of Cases Opened by Priority x Day and the service dashboard's
date range. Retired following the #575 B2 precedent on crm_opportunity: the
report, the case_metrics dataset dimension, the dashboard range and the daily
volume widget, the case_timeline view, the case_sla_defaults resolution-time
chain and the seeds now read or author created_at. The seeds keep their
history because @objectstack/objectql 17.7.0 keeps a seed row's authored
created_at on first insert (objectstack#21646).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zh91QzFgePbkmuHnugLN3
…nd move the case tests to created_at

New test/case-creation-date.test.ts: crm_case declares no created_date, no
locale pack labels it, and every case surface reads created_at; executed on a
real kernel (sqlite-wasm), a case inserted with no date is stamped by the
platform and counted by Cases Opened by Priority x Day and inside the service
dashboard range, and a seed-context row keeps its authored created_at.
The existing case/dashboard tests move their fixtures and predicates from
created_date to created_at, and read a range field's type off the
platform-materialised object (applySystemFields).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zh91QzFgePbkmuHnugLN3
…geset for the created_at move

cases.mdx in all three locales: crm_case declares 24 fields, the SLA & Priority
group loses Created Date, resolution time is measured from the case's creation
moment (the platform's own timestamp), and the Details-tab arithmetic follows
the field count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zh91QzFgePbkmuHnugLN3
….created_date is retired

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zh91QzFgePbkmuHnugLN3
@vercel

vercel Bot commented Oct 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Oct 8, 2026 2:57am UTC

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation ci/cd CI plumbing and the verification pipeline metadata Declarative metadata — schema, security posture, UI surfaces backend Server-side behaviour — hooks, flows, actions labels Oct 8, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 8, 2026 03:04
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit 1e88edc Oct 8, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Server-side behaviour — hooks, flows, actions ci/cd CI plumbing and the verification pipeline documentation Improvements or additions to documentation metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

2 participants