You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2026/08/24 21:10:59 UTC

(causeway) 09/15: archives union projection correctness change

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch htmx
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit e7e2c9a5052e1ae4f57950b1e69a7e30bb2d074f
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Mon Aug 24 13:38:45 2026 +0100

    archives union projection correctness change
---
 .../.openspec.yaml                                 |  0
 .../design.md                                      |  0
 .../evidence/REPRODUCING.md                        |  0
 .../evidence/final-gate-results.md                 |  0
 .../evidence/implementation-report.md              |  0
 .../evidence/production-isolation.md               |  0
 .../evidence/union-shape-matrix.md                 |  0
 .../proposal.md                                    |  0
 .../specs/domain-web-components/spec.md            |  0
 .../spec.md                                        |  0
 .../spec.md                                        |  0
 .../tasks.md                                       |  0
 .../planned-changes/web-component-viewer/README.md |  3 +-
 .../web-component-viewer/vaadin-default-roadmap.md |  4 +-
 openspec/specs/domain-web-components/spec.md       | 50 ++++++++++++++++++++--
 .../spec.md                                        | 36 +++++++++++++++-
 .../spec.md                                        | 19 ++++++++
 17 files changed, 105 insertions(+), 7 deletions(-)

diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/.openspec.yaml b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/.openspec.yaml
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/.openspec.yaml
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/.openspec.yaml
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/design.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/design.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/design.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/design.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/evidence/REPRODUCING.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/REPRODUCING.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/evidence/REPRODUCING.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/REPRODUCING.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/evidence/final-gate-results.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/final-gate-results.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/evidence/final-gate-results.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/final-gate-results.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/evidence/implementation-report.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/implementation-report.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/evidence/implementation-report.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/implementation-report.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/evidence/production-isolation.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/production-isolation.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/evidence/production-isolation.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/production-isolation.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/evidence/union-shape-matrix.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/union-shape-matrix.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/evidence/union-shape-matrix.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/evidence/union-shape-matrix.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/proposal.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/proposal.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/proposal.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/proposal.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/specs/domain-web-components/spec.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/specs/domain-web-components/spec.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/specs/domain-web-components/spec.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/specs/domain-web-components/spec.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/specs/reference-application-viewer-regression-suite/spec.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/specs/reference-application-viewer-regression-suite/spec.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/specs/reference-application-viewer-regression-suite/spec.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/specs/reference-application-viewer-regression-suite/spec.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/specs/rich-graphql-object-interaction-correctness/spec.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/specs/rich-graphql-object-interaction-correctness/spec.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/specs/rich-graphql-object-interaction-correctness/spec.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/specs/rich-graphql-object-interaction-correctness/spec.md
diff --git a/openspec/changes/fix-webcomponent-union-projection-correctness/tasks.md b/openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/tasks.md
similarity index 100%
rename from openspec/changes/fix-webcomponent-union-projection-correctness/tasks.md
rename to openspec/changes/archive/2026-08-24-fix-webcomponent-union-projection-correctness/tasks.md
diff --git a/openspec/planned-changes/web-component-viewer/README.md b/openspec/planned-changes/web-component-viewer/README.md
index 9bb43beab38..d9b6f8635a4 100644
--- a/openspec/planned-changes/web-component-viewer/README.md
+++ b/openspec/planned-changes/web-component-viewer/README.md
@@ -6,7 +6,8 @@ The foundation, domain-component, rich GraphQL correctness, value-semantics, col
 The Reference Application regression suite and input-value hardening changes are archived.
 The action-dispatch correctness change is archived, completing the remaining Priority 0 correction identified by that broad capability inventory.
 The versionless-identity and preparation correction is archived.
-The current active change is `fix-webcomponent-union-projection-correctness`, followed by opaque-route handling before the proposal-only paged-autocomplete and Vaadin-default sequence in `vaadin-default-roadmap.md`.
+The union-projection correction is archived.
+The next change should address opaque-route handling before the proposal-only paged-autocomplete and Vaadin-default sequence in `vaadin-default-roadmap.md`.
 The older Vue, Svelte, metadata, diagnostics, performance-analysis, catalogue, and designer drafts remain queued behind that higher-priority qualification and default-adoption work.
 
 Complete child directories contain `.openspec.yaml`, `proposal.md`, `design.md`, `tasks.md`, and delta specifications and can be promoted verbatim after review.
diff --git a/openspec/planned-changes/web-component-viewer/vaadin-default-roadmap.md b/openspec/planned-changes/web-component-viewer/vaadin-default-roadmap.md
index 828d5dd7918..d640788c5a1 100644
--- a/openspec/planned-changes/web-component-viewer/vaadin-default-roadmap.md
+++ b/openspec/planned-changes/web-component-viewer/vaadin-default-roadmap.md
@@ -8,7 +8,7 @@ The repository permits one active OpenSpec change at a time.
 The Reference Application suite and input-value hardening are archived.
 The archived `fix-webcomponent-action-dispatch-correctness` change completed the remaining Priority 0 correctness tranche identified by the pinned regression corpus.
 The archived `fix-webcomponent-versionless-identity-preparation` change isolates concrete versionless identity.
-The active `fix-webcomponent-union-projection-correctness` change precedes the separate opaque-route correction.
+The archived `fix-webcomponent-union-projection-correctness` change precedes the separate opaque-route correction.
 Proposal-only drafts must be refined against checked-in capability evidence before promotion.
 
 | Order | Proposal | Purpose | Promotion gate |
@@ -16,7 +16,7 @@ Proposal-only drafts must be refined against checked-in capability evidence befo
 | 1 | `add-referenceapp-webcomponent-regression-suite` *(archived)* | Copy the pinned broad corpus, establish deterministic inventory, and expose real gaps. | Completed with reviewed classifications. |
 | 2 | `harden-webcomponent-input-value-semantics` *(archived)* | Correct precision, temporal, nullable, protected, resource, and custom-value behavior independently of toolkit choice. | Completed against stable Reference Application fixtures. |
 | 3 | `fix-webcomponent-action-dispatch-correctness` *(archived)* | Correct nested safe-query and flat mutation dispatch for object and service actions. | Completed with successful typed Reference Application interactions and unchanged public operations. |
-| 4 | `fix-webcomponent-versionless-identity-preparation` *(archived)*, `fix-webcomponent-union-projection-correctness` *(active)*, then focused opaque-route handling | Correct versionless preparation, valid polymorphic metadata selection, and long composite bookmark handling in separate changes. | Each retained gap has an executable focused contract and passing regression target. |
+| 4 | `fix-webcomponent-versionless-identity-preparation` *(archived)*, `fix-webcomponent-union-projection-correctness` *(archived)*, then focused opaque-route handling | Correct versionless preparation, valid polymorphic metadata selection, and long composite bookmark handling in separate changes. | Each retained gap has an executable focused contract and passing regression target. |
 | 5 | `add-paged-graphql-reference-autocomplete` | Add honest server-side reference windows for large datasets. | Public GraphQL operation, identity, preparation, and ordering contracts are accepted. |
 | 6 | `expand-vaadin-semantic-editor-families` | Qualify free-core adapters beyond reference controls with independent lazy closures and CSP gates. | Corrected codecs and Reference Application family journeys pass. |
 | 7 | `make-vaadin-default-for-webcomponent-viewer` | Flip the supported selection policy to Vaadin-first and remove pilot status. | All prerequisite suites pass in default and explicit native modes. |
diff --git a/openspec/specs/domain-web-components/spec.md b/openspec/specs/domain-web-components/spec.md
index 57e7486a6b4..9a288e52734 100644
--- a/openspec/specs/domain-web-components/spec.md
+++ b/openspec/specs/domain-web-components/spec.md
@@ -961,7 +961,51 @@ It MUST preserve advertised identity and presentation fields, MUST treat `versio
 - **THEN** row selection merges the advertised identity fields with requested semantic columns
 - **AND** the rows remain hydratable without manufacturing a concurrency token
 
-#### Scenario: Abstract row type requires fragments
-- **WHEN** an interface or union row cannot expose semantic metadata without concrete fragments
+#### Scenario: Abstract row projection remains unsupported
+- **WHEN** an interface or union row exceeds the bounded projection policy or cannot be resolved through advertised concrete fragments
 - **THEN** the component retains a bounded non-navigable or partial-error result
-- **AND** does not treat versionless concrete-object support as general union-projection support
+- **AND** does not manufacture a concrete identity
+
+### Requirement: Bounded polymorphic value projection
+The component library SHALL derive valid inline-fragment selections for advertised GraphQL interface and union values without selecting concrete fields directly on the abstract type.
+It MUST validate fragment membership and nested fields through targeted introspection, MUST bound fragment and introspection cost, and MUST NOT repeat a mutating interaction to discover its result type.
+
+#### Scenario: Small abstract result has described possible types
+- **WHEN** an interface or union advertises a bounded set of described concrete object types
+- **THEN** the operation selects `__typename` and valid inline fragments for those advertised types
+- **AND** each fragment requests only metadata and children valid for its concrete type
+
+#### Scenario: Broad collection union is activated
+- **WHEN** an activated side-effect-free collection exposes an abstract row type whose complete possible-type set exceeds the direct expansion limit
+- **THEN** the context issues one bounded typename-only probe and describes only distinct observed advertised concrete types
+- **AND** reissues the same list or window read once with valid fragments for those types
+
+#### Scenario: Polymorphic rows expose common identity
+- **WHEN** concrete fragment results contain `id` and `logicalTypeName`
+- **THEN** each row retains its exact typename, metadata, semantic object link, and hydrated row context
+- **AND** optional title and version behavior follows the concrete metadata type
+
+#### Scenario: Requested column differs by concrete type
+- **WHEN** a declared semantic column is present on some observed concrete types and absent on another
+- **THEN** each fragment includes the column only where its wrapper and child selection are advertised
+- **AND** the missing cell remains local without invalidating successfully projected rows
+
+#### Scenario: Replay returns an unobserved concrete type
+- **WHEN** a collection changes between typename probe and fragment replay and returns an advertised type not included in the replay fragments
+- **THEN** that row remains bounded to its available typename projection and is reported locally
+- **AND** the context does not enter an unbounded probe loop
+
+#### Scenario: Returned typename is not advertised
+- **WHEN** a response typename is not an advertised possible type of the abstract field
+- **THEN** the context rejects it as a bounded schema mismatch
+- **AND** does not construct or submit a fragment from that value
+
+#### Scenario: Broad mutating action result
+- **WHEN** a mutating action returns an abstract type that cannot be projected within the direct fragment bound
+- **THEN** the action executes exactly once and retains its successful bounded typename-only outcome
+- **AND** the controller does not invent navigable identity or repeat the mutation
+
+#### Scenario: Polymorphic request becomes obsolete
+- **WHEN** a probe or fragment replay belongs to a disconnected, cancelled, or superseded collection generation
+- **THEN** its remaining work is aborted or discarded
+- **AND** it cannot replace the current row state
diff --git a/openspec/specs/reference-application-viewer-regression-suite/spec.md b/openspec/specs/reference-application-viewer-regression-suite/spec.md
index 75021813932..cd68fb014b9 100644
--- a/openspec/specs/reference-application-viewer-regression-suite/spec.md
+++ b/openspec/specs/reference-application-viewer-regression-suite/spec.md
@@ -137,6 +137,40 @@ It MUST distinguish corrected versionless projection behavior from retained poly
 - **AND** a missing version field is not the cause of any row error
 
 #### Scenario: Unrelated retained gaps remain classified
-- **WHEN** the same qualification run reaches a polymorphic union target or a long opaque composite bookmark
+- **WHEN** the same qualification run reaches an incompatible raw union row or a long opaque composite bookmark
 - **THEN** the suite retains the corresponding bounded known-gap assertion until its focused change is implemented
 - **AND** does not count it as evidence that concrete versionless identity failed
+
+### Requirement: Polymorphic projection regression coverage
+The pinned Reference Application suite SHALL distinguish valid concrete and union projection from a runtime object that is not a member of its advertised union.
+It MUST preserve deterministic concrete-row evidence, bounded schema mismatch behavior, and the separate opaque-route gap.
+
+#### Scenario: Declared type-of collection is activated
+- **WHEN** the browser activates `demo.CollectionTypeOfPage.children`, whose `typeOf` metadata supplies the concrete row type
+- **THEN** concrete `demo.CollectionTypeOfChildVm` rows render their semantic identities through the ordinary concrete projection
+- **AND** union probing is not used for that collection
+
+#### Scenario: Raw collection exposes incompatible runtime rows
+- **WHEN** the companion raw collection is advertised as `rich__demo_ValueHolder__gqlv_union` but returns `demo.CollectionTypeOfChildVm`, which does not implement `demo.ValueHolder`
+- **THEN** GraphQL and the viewer retain a bounded local schema/runtime mismatch
+- **AND** the viewer does not manufacture union membership or an application-specific fragment
+
+#### Scenario: Generated union membership is completed incrementally
+- **WHEN** the Reference Application schema repeatedly discovers concrete `demo.ValueHolder` implementations
+- **THEN** introspection advertises the deterministic merged set rather than only the first registration
+- **AND** every advertised fragment name is a valid member of the completed union
+
+#### Scenario: Invalid direct union metadata is rejected
+- **WHEN** a reproduction selects `_meta` directly from `rich__demo_ValueHolder__gqlv_union`
+- **THEN** GraphQL rejects that operation as invalid
+- **AND** valid viewer planning uses typename and concrete fragments only
+
+#### Scenario: Existing collection behavior remains stable
+- **WHEN** the full collection journey also reaches concrete versionless rows, configured collections, lazy tabs, stale windows, partial errors, and route replacement
+- **THEN** those established behaviors retain their passing assertions
+- **AND** polymorphic planning does not make inactive collections eager
+
+#### Scenario: Opaque composite route remains separate
+- **WHEN** a projected concrete result carries the long opaque identifier retained by the corpus
+- **THEN** the suite continues to assert the focused `invalid-route` gap
+- **AND** does not attribute route rejection to union projection
diff --git a/openspec/specs/rich-graphql-object-interaction-correctness/spec.md b/openspec/specs/rich-graphql-object-interaction-correctness/spec.md
index 8561f20a93d..56809fe6566 100644
--- a/openspec/specs/rich-graphql-object-interaction-correctness/spec.md
+++ b/openspec/specs/rich-graphql-object-interaction-correctness/spec.md
@@ -60,3 +60,22 @@ The correctness changes SHALL preserve established successful concrete-object an
 - **WHEN** an existing concrete object query or scalar action document is executed after the change
 - **THEN** its generated names and semantic result remain compatible
 - **AND** any new type exposure is limited to public logical types required by the corrected contract
+
+### Requirement: Complete incremental union registration
+Rich GraphQL SHALL preserve the union of concrete possible types discovered by every registration of the same generated interface or union name during metamodel construction.
+It MUST deduplicate possible types by GraphQL name and MUST retain one deterministic generated abstract type and resolver registration.
+
+#### Scenario: Later registration discovers another concrete type
+- **WHEN** a generated union name is registered after an existing registration with one or more additional concrete object types
+- **THEN** the schema registry replaces the stored union with merged possible-type membership
+- **AND** introspection advertises both the earlier and later concrete types
+
+#### Scenario: Registration repeats an existing concrete type
+- **WHEN** another registration contributes a concrete type name already present on the generated union
+- **THEN** the stored union contains that type exactly once
+- **AND** schema construction remains deterministic
+
+#### Scenario: Runtime resolver returns a merged concrete type
+- **WHEN** the union resolver identifies a concrete type contributed by a later registration
+- **THEN** GraphQL validates that type against the completed union membership
+- **AND** a client can select it through an advertised inline fragment