You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(rest): preserve the original audit timeline for a historical import (#3493)
Follow-up to #3479/#3483. `treatAsHistorical` skipped the state machine but the
platform still rewrote the timeline: an imported row stamped `updated_at` /
`updated_by` to the import instant, and an `upsert` refresh silently stripped
business `readonly` fields (`closed_at`, `resolved_by`). Reports, audit, and
"recently modified" sorting all came out wrong.
Introduce an opt-in `ExecutionContext.preserveAudit` flag (server-set only) that
`treatAsHistorical` sets alongside `skipStateMachine`, and make the three layers
that force-overwrite the timeline respect it:
- objectql audit hook (plugin.ts): `updated_at` / `updated_by` become
client-preferred (`?? now` / `?? userId`) under preserveAudit, symmetric with
how `created_at` / `created_by` already behave on insert.
- objectql readonly strip (rule-validator.ts): admits a WHITELIST — the
audit/timestamp family plus author-declared business `readonly` fields — while
platform-managed `system` columns outside that family (`organization_id` /
tenancy, generated columns) stay stripped. A whitelist, not the blanket
`isSystem` exemption, so it is not a tenancy-forging backdoor.
- driver-sql update: keeps a supplied `updated_at` instead of force-advancing it
to `now` (`DriverOptions.preserveAudit`).
Fully opt-in: a normal write still auto-stamps and strips exactly as before.
Permissions / RLS / field-level security are unaffected. The objectui "Import as
historical data" checkbox (objectui#2815) now drives both halves — no new UI.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B5rdfBKjkbcoEif4KUV6xE
0 commit comments