Skip to content

Commit 471daa3

Browse files
alicodingclaude
andauthored
docs: goal 0046 queued — schema evolution without breaking history (#91)
Owner-raised from a regulated-platform incident; research-backed design sketch recorded (identity/label split, no in-place retype, tombstone deletes, Decision versioning per ADR-0021's shape, per-run version stamps). Verified baseline: workflow-owned Attributes already snapshot-safe, Configure entities live-referenced — the gap the ADR this goal opens with must close. Claude-Session: https://claude.ai/code/session_01FJ8wStsHyu7XPLTspNjMnQ Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 13822f8 commit 471daa3

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Goal 0046 — Schema evolution: rename/retype/delete without breaking history
2+
3+
Owner-raised 2026-08-13 from a real incident on a commercial
4+
decision-automation platform used in regulated enterprises: its
5+
attribute schemas map to physical database columns, so renames are
6+
forbidden, deletes are undocumented soft-deletes, a mis-chosen field
7+
type is permanent, and — because workflows reference the single LIVE
8+
decision definition rather than a version — retiring one decision
9+
required manually clearing references across ~30 historical workflow
10+
versions. Research pass delivered same day (agent-run, primary
11+
sources: Camunda DMN versioning, Confluent Schema Registry
12+
soft/hard-delete + compatibility modes, Avro/Protobuf evolution
13+
rules, event-sourcing upcasters, expand/contract migrations; full
14+
report in the session transcript, verdicts summarized here).
15+
16+
## Verified Mill baseline (from code, not assumed)
17+
18+
- SAFE ALREADY: workflow-owned `Attributes` freeze into each
19+
published `WorkflowVersion` (ADR-0021 `SnapshotHead`); run history
20+
stores attribute values schema-on-read (`map[string]any` in the
21+
run's own JSON), so live-schema edits can never corrupt old runs.
22+
- THE GAP: Configure entities are live-referenced. A
23+
`decision-outcome` node stores only `decisionId` and resolves
24+
against the CURRENT `Decision.Outputs` on every execution — even
25+
when the workflow itself is version-pinned. `DeleteDecision` has no
26+
reference-integrity check (dangling IDs fail at run time).
27+
`typedfield.Field.Key` is simultaneously identity and name (a
28+
rename is structurally delete+add); `Field.Label` exists but isn't
29+
the guaranteed-renamable surface. Same live-reference class:
30+
`requestId`/`listId`/`mcpServerId` (ADR-0009 RefKinds).
31+
`.claude/rules/node-standard.md` already names the sibling gap for
32+
`NodeType.ConfigFields` (latent, not built).
33+
34+
## Design direction (research-backed sketch — the ADR this goal opens
35+
with decides it; not pre-resolved here)
36+
37+
1. Identity/label split: `Field.Key` immutable after first save
38+
(enforcement precedent: `Decision.Category`'s existing
39+
server-side immutability), `Label` freely renamable — Protobuf
40+
field-number / Avro-alias insight, near-free since both fields
41+
exist.
42+
2. Retype: never in place (no adopted system allows it); "add new
43+
field + deprecate old" as the guided path, optionally a narrow
44+
safe-promotion set.
45+
3. Delete: tombstone-not-drop for schema fields, reusing
46+
`internal/services/seeding`'s existing tombstone mechanism; hard
47+
delete of a referenced Configure entity blocked or made soft.
48+
4. Shared-entity versioning: give `Decision` the same
49+
Versions/Publish shape `Workflow` already has (ADR-0021 applied
50+
to a second entity type), with an optional pinned-version config
51+
on `decision-outcome` (precedent: `child-workflow`'s `version`).
52+
5. Stamp the resolved definition version onto each run record
53+
(precedent: `runInput.Version`) — the audit-replay guarantee
54+
("what did this decision look like when this run executed")
55+
preserved exactly, without freezing the live definition.
56+
57+
## Acceptance (checkable)
58+
59+
- [ ] An ADR decides the rename/retype/delete/versioning semantics
60+
(the sketch above is its input, not its conclusion), including
61+
which parts apply to ALL RefKind entities vs. Decision first.
62+
- [ ] The decided semantics implemented with the standing proof
63+
discipline (unit + seeded-example + e2e per testing.md's
64+
layering), including a regression proving a version-pinned
65+
workflow resolves the pinned definition after the live one
66+
changes.
67+
- [ ] Reference-integrity at delete time: deleting a still-referenced
68+
Configure entity is blocked or soft per the ADR — never a
69+
run-time-only failure.
70+
- [ ] SPEC.md updated (the typed-system section gains the evolution
71+
semantics; any OPEN it resolves is surfaced first).

docs/goals/BACKLOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ accepted)**
4949
live and attestation-verified. The cut surfaced and fixed three
5050
more latent defects (raw-binary asset, release.yml invalid YAML —
5151
now gated by workflow-lint, GPL-3 setup-task action wrapper)
52+
5. [ ] [0046 — Schema evolution](0046-schema-evolution.md)
53+
owner-raised from a real regulated-platform incident
54+
(rename-forbidden / retype-permanent / live-referenced decisions
55+
forcing a ~30-version manual cleanup); research delivered
56+
2026-08-13 with a five-part design sketch reusing ADR-0021's
57+
versioning, seeding's tombstones, and the Field Key/Label split;
58+
opens with the ADR that decides the semantics. Verified gap:
59+
Mill's Configure entities are live-referenced (a pinned workflow
60+
still resolves TODAY's decision definition) and deletes have no
61+
reference-integrity check
5262

5363
**Group E — Public-repo hygiene (2026-08-13, owner-directed: source
5464
comments explain code per standard practice — business/product

0 commit comments

Comments
 (0)