Skip to content

docs(adr): amend ADR-0028 — a concrete projection owns its source - #272

Merged
dmealing merged 1 commit into
mainfrom
fix/projection-source-doctrine-and-270
Aug 6, 2026
Merged

docs(adr): amend ADR-0028 — a concrete projection owns its source#272
dmealing merged 1 commit into
mainfrom
fix/projection-source-doctrine-and-270

Conversation

@dmealing

@dmealing dmealing commented Aug 6, 2026

Copy link
Copy Markdown
Member

Records the doctrine behind ERR_PROJECTION_INHERITED_SOURCE (shipped in bdeb4765): a concrete object.projection declares its own source.*; an abstract projection base carries shape only.

Why this needed writing down

The rule looks arbitrary until you see which of two inheritance regimes a projection belongs to — and the prior art is decisive on the split:

regime binding inherited? writability inherited? examples
shared storage yes yes, with the binding Hibernate @Immutable (inherited by entity subclasses), EF Core keyless ToView, SQLAlchemy single-table
shape reuse no n/a — the concrete class binds its own JPA @MappedSuperclass ("has no separate table defined for it"), Django abstract bases

A projection is the second kind. Django documents inheriting db_table from an abstract base as a trap in almost these words: "all the child classes … would use the same database table, which is almost certainly not what you want." No surveyed system permits the unguarded middle MetaObjects had — binding inherited, kind not.

Also records why the fix guards the shape rather than flipping a predicate. "Which source am I bound to" is resolving because entities legitimately inherit their table (TPH / BaseEntity); "what KIND of source am I" is own-only because projection-ness belongs to the declaring object. Both are correct for what they were designed for — only their intersection was incoherent, and it produced no working artifact in any of the five ports (TS mounted writable CRUD over a read-only view; Java/Kotlin skipped on subtype; Python on resolved kind; C# emitted nothing).

Also here

The metaobjects-authoring skill gains the rule plus its sanctioned pattern — abstract sourceless base, each concrete projection declaring its own view — so an agent authoring a versioned projection declares v_customers_v2 instead of silently sharing V1's view. Bundled into the sdk copy and the four agent-context-conformance goldens.

Not included: #270

#270 was scoped as "retire the redundant Kotlin/Python payload origin-typing." Its premise is falsified the same way #271's was. The redundancy claim holds for origin.passthrough (type-preserving since #185) but not for origin.aggregate (countLong, avgDouble) or origin.collection (→List<TargetPayload>), where the origin genuinely determines the type and the declared field type cannot express it. The corpus exercises exactly those — origin-collection-simple and flattened-kitchen-sink both carry origins on object.value. Deleting the handling would not be byte-identical; it would either break type derivation or make Kotlin match TS's origin-blindness, which may itself be the defect rather than the baseline. Needs its own recon before anything is deleted.

Gates

Docs + skill only — no product code. TS typecheck clean; sdk suite green (150); agent-context goldens regenerated and matching.

Records the doctrine behind ERR_PROJECTION_INHERITED_SOURCE (bdeb476): a
concrete object.projection declares its own source.*; an abstract projection base
carries shape only.

The rationale is worth writing down because the rule looks arbitrary until you see
which of two inheritance regimes a projection belongs to. Shared-storage
inheritance inherits binding AND writability together — Hibernate's @immutable is
inherited by entity subclasses, EF Core keyless ToView types, SQLAlchemy
single-table. Shape-reuse inheritance does not inherit the binding at all — JPA
@MappedSuperclass has no table of its own, and Django documents inheriting
db_table from an abstract base as a trap, in almost these words. A projection is
the second kind, so the concrete class must bind its own storage.

Also records why the fix guards the shape instead of flipping a predicate: "which
source am I bound to" is resolving because entities legitimately inherit their
table, "what KIND of source am I" is own-only because projection-ness belongs to
the declaring object, and both are right for what they were designed for. Only
their intersection was incoherent, and it produced no working artifact in any of
the five ports.

The authoring skill gains the rule with its sanctioned pattern (abstract sourceless
base, concrete projections declaring their own views) so an agent authoring a
versioned projection declares v_customers_v2 rather than silently sharing V1's
view. Bundled into the sdk copy and the four agent-context-conformance goldens.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3msoGxjRMwx94PhKSLDuE
@dmealing
dmealing merged commit 780fb30 into main Aug 6, 2026
1 check passed
@dmealing
dmealing deleted the fix/projection-source-doctrine-and-270 branch August 6, 2026 12:21
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