Skip to content

spec: history — the shadow change trail - #17

Open
delchev wants to merge 1 commit into
mainfrom
spec/history-trail
Open

spec: history — the shadow change trail#17
delchev wants to merge 1 commit into
mainfrom
spec/history-trail

Conversation

@delchev

@delchev delchev commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

audit: true records only the last writer and time, in four columns of the row itself. A domain
that has to answer what changed, from what to what, by whom, when — for every write, for years —
had no construct for it; the 1.1 "Planned" list named shadow audit-history entities, and this is
that construct.

What it adds

A ### history — the change trail section in versions/1.2.md, plus the entity-attribute row and
the Appendix A: DSL index row; the "Planned" entry loses the item.

- name: Contract
  audit: true
  history: true

The entity gains a shadow history table — a sibling of its own table, like the multilingual
language table — carrying one entry per property whose value actually changed on a write: the
property, its old value, its new value, who wrote it, when, and whether the write came from a user
or from the system. A create is null -> value and a delete value -> null, so the trail alone
reconstructs the row at any point in its life; the record's own form shows it as a read-only History
panel.

The normative rules, and why each one is there

  • Append-only by construction — no create, update or delete path may be emitted for the shadow
    table, not a service, not an endpoint, not a UI affordance. Append-only enforced by policy is not
    append-only.
  • Every write path appends, including the targeted single- and multi-column writes the system
    uses. A path that writes silently is worse than no trail, because the trail then reads as complete.
  • The source is recorded. Once a total the application recomputed and an amount a person typed
    sit in the same column, nothing downstream can tell them apart.
  • Representation-only differences are not changes — a decimal of another scale, a translated
    overlay of a stored value. Otherwise the trail fills with edits nobody made.
  • The primary key and the audit columns are not tracked — they restate what the entry carries.
  • A scoped surface that hides sensitive: fields is not handed a trail it cannot filter — either
    the trail excludes those properties or the surface exposes none. Leaking a hidden field's old and
    new values defeats the scoping exactly.
  • Rows written outside the generated data-access layer have no history, and a conforming tool
    says so rather than implying completeness.

Reference implementation

eclipse-dirigible/dirigible#6734 — schema-level shadow table, appends on every repository write path
with the user/system attribution, GET /{id}/history, the History panel, and an end-to-end test
covering both the user and the system side.

Left open for maintainer review.

`audit: true` records only the last writer and time, in four columns of the row
itself. A domain that has to answer what changed, from what to what, by whom and
when - for every write - had no construct; the 1.1 "Planned" list named shadow
audit-history entities.

`history: true` on an entity declares a shadow history table: one entry per
property whose value actually changed on a write, carrying the property, its old
and new value, who wrote it, when, and whether the write came from a user or from
the system. A create is null -> value and a delete value -> null, so the trail
alone reconstructs the row at any point in its life.

Normative rules: the table is append-only by construction (no create, update or
delete path may be emitted for it - append-only enforced by policy is not
append-only); every write path the data-access layer offers must append,
including the targeted writes the system uses; the entry records the source;
representation-only differences (a decimal of another scale, a translated
overlay) are not changes; the primary key and the audit columns are not tracked;
and a scoped surface that hides sensitive fields is not handed a trail it cannot
filter.

Reference implementation: eclipse-dirigible/dirigible#6734.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant