Skip to content

feat(lifecycle): ADR-0057 P1–P4 — lifecycle contract, Reaper/Rotator/Archiver, datasource separation, governance (#2786) - #2791

Merged
os-zhuang merged 7 commits into
mainfrom
claude/adr-0057-data-lifecycle-azuf45
Jul 11, 2026
Merged

feat(lifecycle): ADR-0057 P1–P4 — lifecycle contract, Reaper/Rotator/Archiver, datasource separation, governance (#2786)#2791
os-zhuang merged 7 commits into
mainfrom
claude/adr-0057-data-lifecycle-azuf45

Conversation

@os-zhuang

@os-zhuangos-zhuang commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Implements ADR-0057 data lifecycle P1–P4 (tracking issue #2786) — platform-generated data becomes bounded by construction. Grew out of the 260 MB dev.db incident: every platform-generated object defaulted to immortal, and the file never shrank.

P1 — contract (spec, objectql, driver-sql)

  • New lifecycle object property: class: record | audit | telemetry | transient | event + retention.maxAge / ttl.{field, expireAfter} / storage(rotation) / archive.{after, to, keep} / reclaim, with duration literals ('6h', '14d', '7y'). Parse-time invariants (ADR §3.5 enforce-or-remove): a non-record class with no bounding policy is rejected; policies on record are rejected; archive.after must equal retention.maxAge.
  • LifecycleService registered by ObjectQLPlugin (platform-owned, default-on; OS_LIFECYCLE_DISABLED=1 or lifecycle.enabled=false to opt out). The Reaper bulk-deletes rows past retention.maxAge/ttl hourly under a system context — one afterDelete hook max per object per sweep, and telemetry sys_* objects are in the audit writer's SKIP_OBJECTS, so cleanup never re-feeds the tables it drains (ADR-0052 self-audit trap).
  • SqlDriver.reclaimSpace() — the PRAGMA incremental_vacuum hook the ADR's P0 text described but which had never actually landed.
  • 11 platform objects annotated: sys_activity 14d+rotation, sys_audit_log 90d→archive 7y, sys_metadata_audit 365d→archive, sys_job_run/sys_automation_run/sys_http_delivery 30d, notification pipeline (event/delivery/receipt/inbox) one 90d window, sys_device_codeexpires_at+1d.
  • Gates: spec-liveness classifies object/lifecycle and binds it to a dogfood proof (HIGH_RISK_CLASSESdata-lifecycle); new dogfood storage-growth gate (@proof: adr0057-lifecycle-bounded-growth) boots showcase, reaps a backdated runaway writer, and asserts record-class data is untouched.

P2 — Rotator (driver-sql)

storage: { strategy: 'rotation', shards, unit } physically time-shards the table on SQLite (ServiceNow Table Rotation model): writes land in the current shard (<table>__r<key>), reads go through a UNION-ALL view under the base name, expiry is an O(1) DROP of shards past the shards × unit window. Legacy tables are adopted as the first shard on upgrade (no data loss); by-id and bulk writes fan out shard-wise; other dialects fall back to an equivalent age-based reap so the declared bound holds everywhere. (Transient TTL expiry shipped with the P1 Reaper — TTL and age reaping are one mechanism per §3.3.)

P3 — separation + Archiver (objectql)

  • Registering a datasource named telemetry routes telemetry/event/audit objects to it (engine getDriver step 3; opt-in purely by the datasource's existence). transient deliberately stays on the primary — some of those objects (better-auth's sys_device_code) are accessed outside the engine.
  • Archiver: audit objects with archive declared get retain → archive → delete — batched idempotent copies to the cold store, hot-delete of exactly the copied ids, archive.keep pruning of the archive itself. Hard rule: no archive datasource ⇒ rows retained and reported archive-pending; a compliance ledger is never dropped unarchived.

P4 — governance (objectql + settings)

New lifecycle settings namespace: runtime enable switch, retention_overrides (tenant-scoped — regulated tenants set years, dev sets days, ADR §3.2; per-tenant windows sweep each overriding tenant on its own cutoff while the global pass covers everyone else including NULL-org rows), quotas/quota_defaults and growth_alert_rows — quota/growth breaches are observe-and-alert only (report.alerts + onAlert sink), never deletion beyond declared policy.

Verification

  • 26 LifecycleService unit tests (Reaper/Rotator/Archiver/governance), 5 driver rotation tests, 3 datasource-routing tests, 9 spec schema tests
  • Dogfood storage-growth gate: 6 end-to-end cases through a real showcase boot (contract coverage, reap, rotation via engine→driver, archive-safety, hot→cold drain to a real second SQL store)
  • Full test suites of all 11 touched packages green (68 turbo tasks, incl. the complete dogfood suite); spec-liveness gate green

Also included: the initial doc-only commit syncing the ADR header (P0 shipped in #2079), and a final commit marking §4 P1–P4 implemented + the changeset (all minor, per the launch-window convention).

Closes#2786.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3

…racked in #2786
The ADR header still said 'Proposed' with no pointer to the shipped P0
implementation or the new P1–P4 tracking issue. Per repo convention
(cf. ADR-0030/0055/0069 headers), reflect implementation reality:
- Status: Accepted — P0 shipped with this ADR (#2079); P1–P4 proposed,
tracked in #2786
- §4 Rollout: link #2079 on the P0 row; add the #2786 tracking pointer
Doc-only change; no code or policy content altered.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
@vercel

vercelBot commented Jul 10, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 10, 2026 3:30pm

Request Review

claude added 5 commits July 10, 2026 14:45
…eaper, liveness gate, dogfood growth gate (#2786)
The platform can declare an object's structure, validations and permissions —
but not how long its data lives. P1 makes data lifecycle a first-class,
declarable, runtime-enforced metadata concern:
spec:
- `lifecycle` object property (LifecycleSchema): class (record | audit |
telemetry | transient | event) + retention.maxAge / ttl / storage(rotation)
/ archive / reclaim, with duration literals ('6h', '14d', '7y')
- §3.5 enforce-or-remove invariants in a superRefine: a non-record class with
no bounding policy is rejected; record-class policies are rejected; the
archive window must start where the hot window ends
- IDataDriver.reclaimSpace?() contract for post-sweep space reclamation
objectql:
- LifecycleService (Reaper), registered by ObjectQLPlugin as a platform
service (default-on, OS_LIFECYCLE_DISABLED=1 / lifecycle.enabled=false to
opt out): hourly sweep deletes rows past retention.maxAge (created_at) and
past ttl.field + expireAfter, bounds rotation-declared telemetry by
shards×unit until the P2 Rotator lands, and never hot-deletes an
archive-declared audit ledger before the Archiver copies it out
- Sweeps run bulk multi-deletes under a system context — at most ONE
afterDelete hook per object per sweep, and telemetry sys_* objects are in
the audit writer's SKIP_OBJECTS, so cleanup never re-feeds the tables it
drains (the ADR-0052 self-audit trap)
driver-sql:
- reclaimSpace(): SQLite `PRAGMA incremental_vacuum` (the P0 ADR text
claimed this hook shipped; it had not — this closes it), no-op on
Postgres/MySQL
platform objects (11 annotated): sys_activity 14d+rotation,
sys_audit_log 90d→archive 7y, sys_metadata_audit 365d→archive,
sys_job_run/sys_automation_run/sys_http_delivery 30d, notification pipeline
(sys_notification / delivery / receipt / inbox) one 90d window,
sys_device_code expires_at+1d.
gates:
- spec-liveness: object/lifecycle classified + bound to a dogfood proof
(HIGH_RISK_CLASSES 'data-lifecycle')
- dogfood storage-growth gate (@proof: adr0057-lifecycle-bounded-growth):
boots showcase, proves contract coverage, reaps a backdated runaway
writer, asserts record-class data untouched and archive-declared ledgers
retained
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
…(1) shard DROP (#2786)
High-frequency telemetry declared with lifecycle.storage.strategy='rotation'
is now physically time-sharded on SQLite (the ServiceNow Table Rotation
model, ADR-0057 §3.3):
driver-sql:
- rotateShards(objectDef, nowMs): idempotent Rotator entry — ensures the
current shard (<table>__r<key>: day/week/month UTC keys), adopts a legacy
pre-rotation table as its first shard (no data loss), column-syncs every
retained shard so the UNION stays uniform, DROPs shards past the
shards×unit time window (O(1) reclaim), and rebuilds the read view
- The base name becomes a READ-ONLY UNION ALL view (SQLite views reject
writes and RETURNING), so every write path redirects shard-wise instead:
create/bulkCreate/upsert target the current shard; by-id update/delete
probe shards newest-first; updateMany/deleteMany/bulkDelete fan out and
sum — reads (find/count/aggregate) are untouched
- Per-shard bookkeeping aliases (datetime/date/json/boolean coercion, tenant
scope, timestamp stamping) so a shard builder behaves exactly like the view
- initObjects routes rotation-declared objects to the Rotator (the plain
create/alter DDL path would collide with the view)
- supportsRotation gates on the dialect; declared indexes get per-shard names
objectql LifecycleService:
- Rotator invocation each sweep when the driver supports it; the fallback
age-based reap covers every other dialect so the declared bound holds
everywhere, only the reclamation mechanics differ
- An explicit retention.maxAge still trims inside live shards after rotation
(shard drops are unit-granular; this also immediately bounds a legacy
table the Rotator just adopted whole)
- Dropped shards trigger the datasource incremental-vacuum pass
Transient TTL expiry (the other P2 line item) shipped with the P1 Reaper —
TTL and age reaping are one mechanism (§3.3).
Proof: sql-driver-rotation.test.ts drives the full shard lifecycle (create →
rotate → window drop → adoption → cross-shard writes); the dogfood
storage-growth gate now shards a probe stream through the real
engine→driver path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
…store (#2786)
Separation (§3.6): objects whose lifecycle.class is telemetry / event /
audit now route to a dedicated 'telemetry' datasource whenever one is
registered — engine getDriver() step 3, between datasourceMapping rules and
the package-manifest defaultDatasource. Opt-in purely by the datasource's
existence: no 'telemetry' driver ⇒ resolution is byte-for-byte what it was.
Even on SQLite that is a separate file, so platform-generated growth can
never again pollute the business DB. 'transient' deliberately stays on the
primary: those objects are user-session data and some (better-auth's
sys_device_code) are accessed outside the engine — splitting their storage
would split their brain.
Archiver (§3.3): audit-class objects with 'archive' declared now get the
full retain → archive → delete flow instead of the P1 retain-only skip:
- copies rows past archive.after to the archive datasource in bounded
batches (500 × 20/sweep — a backlog drains across sweeps), as per-row
idempotent upserts so an interrupted sweep re-converges
- hot-deletes exactly the copied ids (bulkDelete), then the reclaim pass
vacuums the hot store
- archive.keep prunes the cold store itself
- the cold schema is mirrored via idempotent syncSchema
- no archive datasource registered ⇒ rows retained, object reported
'archive-pending' — a compliance ledger is never dropped unarchived
Proof: engine-lifecycle-datasource.test.ts (routing incl. explicit-datasource
precedence), Archiver unit tests (copy/delete id-exactness, keep-pruning,
missing-datasource retention), and a dogfood case that provisions a real
second SQL store mid-run and watches the ledger drain hot → cold.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
…ant retention overrides (#2786)
Adds the operations layer over the P1-P3 enforcement machinery, resolved
from a new 'lifecycle' settings namespace (registered by ObjectQLPlugin at
kernel:ready when a SettingsService is present; absent settings = declared
policies apply unmodified):
- enabled — runtime master switch (on top of OS_LIFECYCLE_DISABLED)
- retention_overrides — per-object window overrides { object: { maxAge,
expireAfter } }. TENANT-scoped: the sweep enumerates organizations, and a
tenant whose override is genuinely tenant-scoped (not inherited) gets its
own cutoff on its own rows, while the global pass covers everyone else
INCLUDING NULL-org rows (a bare $nin would silently skip them). This is
ADR-0057 §3.2 verbatim: regulated tenants set years, dev sets days — the
same knob at different settings. An unparseable override keeps the
declared window (never fails open into unbounded growth).
- quotas / quota_defaults — per-object and per-class row ceilings
- growth_alert_rows — per-sweep growth spike threshold
Quota and growth breaches are OBSERVE-AND-ALERT only (report.alerts +
onAlert sink, default logger warning) — governance never deletes beyond the
declared policy; an operator decides.
Every settings read is best-effort and snapshotted once per sweep; the
tenant scan is capped (200) and skipped entirely on single-tenant kernels.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
… lifecycle release (#2786)
- ADR-0057 header + §4 rollout table now record P1–P4 as implemented in
#2791; §3.3 gains the archive-safety hard rule and §3.6 the as-implemented
'telemetry' datasource routing note (transient exclusion rationale).
- Changeset: minor bumps across spec / objectql / driver-sql /
driver-sqlite-wasm / platform-objects / metadata-core / service-messaging /
service-automation / plugin-audit, documenting the bounded-by-default
behavior change and the override knobs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 8 package(s): @objectstack/dogfood, @objectstack/metadata-core, @objectstack/objectql, @objectstack/platform-objects, @objectstack/driver-sql, @objectstack/plugin-audit, packages/services, @objectstack/spec.

104 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via packages/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via packages/services, @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via @objectstack/metadata-core, @objectstack/objectql, packages/spec)
  • content/docs/concepts/north-star.mdx(via packages/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/driver-sql, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via packages/objectql, @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/migration-from-objectql.mdx(via @objectstack/objectql)
  • content/docs/deployment/production-readiness.mdx(via @objectstack/plugin-audit)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/vercel.mdx(via @objectstack/objectql)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/cli.mdx(via @objectstack/plugin-audit, @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/glossary.mdx(via @objectstack/driver-sql)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via packages/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/audit-service.mdx(via packages/services)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/services, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/settings-service.mdx(via packages/services)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via packages/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx(via @objectstack/objectql)
  • content/docs/permissions/authorization.mdx(via packages/dogfood, @objectstack/spec)
  • content/docs/permissions/delegated-administration.mdx(via packages/dogfood)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/anatomy.mdx(via @objectstack/driver-sql)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/objectql, @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/objectql, @objectstack/platform-objects, @objectstack/driver-sql, @objectstack/plugin-audit, packages/services, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx(via packages/services, @objectstack/spec)
  • content/docs/protocol/objectos/index.mdx(via @objectstack/objectql, @objectstack/driver-sql)
  • content/docs/protocol/objectos/lifecycle.mdx(via @objectstack/driver-sql, @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/objectql, @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx(via @objectstack/objectql, @objectstack/driver-sql, @objectstack/plugin-audit, @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/objectql, @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/platform-objects, @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuangos-zhuang changed the title docs(adr): ADR-0057 header/rollout sync — P0 shipped (#2079), P1–P4 tracked in #2786feat(lifecycle): ADR-0057 P1–P4 — lifecycle contract, Reaper/Rotator/Archiver, datasource separation, governance (#2786)Jul 10, 2026
…le exports
The 5 additions (LifecycleSchema / LifecycleClassSchema / Lifecycle /
LifecycleClass / LIFECYCLE_DURATION_REGEX) are the intentional P1 spec
surface; the api-surface gate flagged them as uncommitted snapshot drift.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
@os-zhuang
os-zhuang marked this pull request as ready for review July 11, 2026 01:31
@os-zhuang
os-zhuang merged commit 7953832 into mainJul 11, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/adr-0057-data-lifecycle-azuf45 branch July 11, 2026 01:32
os-zhuang pushed a commit that referenced this pull request Jul 11, 2026
…gistry conflicts
Both this branch and the merged ADR-0057 lifecycle work (#2791) appended a
HIGH_RISK_CLASSES entry and extended the BOUND_PROOF_PATHS expectation:
kept BOTH ('delegation' → position/delegatable, 'data-lifecycle' →
object/lifecycle). proof-registry tests and the spec-liveness gate pass on
the merged tree.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
os-zhuang added a commit that referenced this pull request Jul 11, 2026
…ow-up) (#2818)
The lifecycle contract shipped in #2791 with no hand-written docs or skill
coverage — anyone modeling an append-only object through the docs or the
objectstack-data skill would still build the unbounded-growth bug the ADR
exists to prevent. Four gaps closed:
- data-modeling/objects.mdx: "Data Lifecycle (Retention & Rotation)" under
Enterprise Features — classes, three valid policy examples (each verified
against the real LifecycleSchema parse), enforcement rules, archive
safety, telemetry-datasource separation, and the governance knobs.
- kernel/services.mdx: `lifecycle` row in the Standard Services table.
- data-modeling/drivers.mdx: SQLite space reclamation (auto_vacuum +
reclaimSpace) and physical table rotation; PG/MySQL fallback semantics.
- deployment/production-readiness.mdx: go-live checklist item — review the
default retention windows / tenant overrides / archive datasource before
launch.
- skills/objectstack-data: new rules/lifecycle.md (decision tree,
correct/incorrect examples, ops table) + SKILL.md property-table row and
Quick Reference link, explicitly disambiguated from lifecycle *hooks*.
Docs/skills only — no runtime change, no changeset (skip-changeset).
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
Co-authored-by: Claude <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 11, 2026
…v telemetry datasource + db:clean, Studio lifecycle form (#2835)
Implements #2834 ①–③ (④ PG-partition rotation design-sketched on the issue, deferred until CI has a PostgreSQL service).
① JobRunRetention / NotificationRetention and their retentionDays/retentionSweepMs options removed — the LifecycleService is the one sweeper (windows tuned via the lifecycle settings namespace). Includes a fix: the blanket 30d lifecycle retention on sys_automation_run (from #2791) could strand suspended approval runs; removed — bounding stays with the automation store's terminal-only sweep.
② objectstack dev provisions a dedicated telemetry datasource (<primary>.telemetry.db; OS_TELEMETRY_DB to opt out/override) and new `os db clean` runs the one-time VACUUM legacy files need to adopt auto_vacuum=INCREMENTAL.
③ object.form.ts exposes the lifecycle block; metadata-forms i18n bundles regenerated with curated zh-CN.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/xlteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ADR-0057 data lifecycle P1–P4: retention contract, rotation, separation, governance (tracking)

2 participants

@os-zhuang@claude