Skip to content

feat(audit): declarative field-change activity via trackHistory (ADR-0052 §5b)#1948

Merged
os-zhuang merged 2 commits into
mainfrom
feat/adr-0052-declarative-activity
Jun 16, 2026
Merged

feat(audit): declarative field-change activity via trackHistory (ADR-0052 §5b)#1948
os-zhuang merged 2 commits into
mainfrom
feat/adr-0052-declarative-activity

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What

Platform-layer P0a from ADR-0052 §5b ("Declarative activity, not per-app code"). Lets apps declare their activity timeline instead of hand-coding hooks/flows that insert sys_activity rows.

The audit-writer already computes the field diff (diff(before, after) → stored in the activity metadata) but renders a flat, useless "Updated crm_opportunity" summary. This adds a per-field opt-in flag and renders the diff it already has, legibly.

  • spec: trackHistory?: boolean on the field schema. Reintroduces the concept of the pruned auditTrail flag, but with a runtime consumer — satisfying enforce-or-remove (ADR-0049).
  • plugin-audit (audit-writers.ts): when a changed field declares trackHistory: true, the activity summary becomes "Stage: Proposal → Closed Won" (field label + select option labels; multiple changes joined by ; ). Falls back to the generic "Updated <object>" when no tracked field changed — no behavior regression.

Prior art

Same posture as Salesforce Feed Tracking / Field History Tracking, ServiceNow dictionary Audit + Activity Formatter, Dataverse per-column auditing + Timeline: declarative per-field opt-in → platform auto-generates the human-readable change entry; imperative code reserved for genuinely semantic events.

Verification

  • @objectstack/plugin-audit build (ESM+CJS+DTS) ✓, 16/16 tests pass (2 new: renders label/option diff; falls back when only untracked fields change).
  • @objectstack/spec build ✓.

Why this matters

The hand-coded activity hooks/actions in hotcrm#396 are exactly what this declarative layer subsumes. Once this ships and HotCRM adopts it, stage/status/priority get trackHistory: true and the opportunityActivityHook (and most hand-coded activity) is deleted. Follow-on tiers (object-level milestone templates; event-bus projection for email/call/meeting) are specified in ADR-0052 §5b.2–3.

🤖 Generated with Claude Code

…0052 §5b)

The activity writer already captures the field diff but renders a flat
"Updated <object>" summary. Add a per-field `trackHistory` flag (spec) and wire
the audit-writer to render tracked changes legibly — "Stage: Proposal → Closed
Won" — using the field label and select option labels. Opt-in per field (cf.
Salesforce Feed Tracking / ServiceNow field auditing / Dataverse column
auditing). Reintroduces the pruned `auditTrail` concept WITH a runtime consumer,
satisfying enforce-or-remove (ADR-0049).

Apps can now DECLARE their timeline instead of hand-coding hooks/flows that
insert sys_activity rows.

- spec: trackHistory?: boolean on the field schema
- plugin-audit: renderTrackedChangeSummary + getFieldDefs; update summary uses
  it, falling back to the generic text when no tracked field changed
- tests: 2 new cases (renders label/option diff; falls back when untracked)
- docs: ADR-0052 §5b "Declarative activity, not per-app code"

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 16, 2026 7:27am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests size/m labels Jun 16, 2026
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-audit, @objectstack/spec.

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

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/plugin-audit, @objectstack/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 packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/plugin-audit, @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-audit, @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/spec)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/spec)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/plugin-audit, @objectstack/spec)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/spec)
  • content/docs/guides/production-readiness.mdx (via @objectstack/plugin-audit)
  • content/docs/guides/project-scoping.mdx (via @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/skills.mdx (via @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/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 @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @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/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/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @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.

The liveness ratchet (ADR-0049) correctly flagged the new `trackHistory` field
property as undeclared surface. It has a runtime consumer
(plugin-audit audit-writers), so classify it `live` with evidence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/m tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant