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/23 09:16:57 UTC

(causeway) 22/22: archives input value semantics hardening

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 18f0a783d249731cf3686c6ddd859ac70a02a523
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Aug 23 10:06:36 2026 +0100

    archives input value semantics hardening
---
 .../.openspec.yaml                                 |  0
 .../design.md                                      |  0
 .../evidence/REPRODUCING.md                        |  0
 .../evidence/final-gate-results.md                 |  0
 .../evidence/input-capability-inventory.md         |  0
 .../evidence/production-isolation.md               |  0
 .../evidence/value-semantics-contract.md           |  0
 .../proposal.md                                    |  0
 .../specs/domain-web-components/spec.md            |  0
 .../specs/rich-graphql-value-semantics/spec.md     |  0
 .../tasks.md                                       |  0
 openspec/specs/domain-web-components/spec.md       | 90 ++++++++++++++++++++++
 .../specs/rich-graphql-value-semantics/spec.md     | 89 +++++++++++++++++++++
 13 files changed, 179 insertions(+)

diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/.openspec.yaml b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/.openspec.yaml
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/.openspec.yaml
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/.openspec.yaml
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/design.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/design.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/design.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/design.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/evidence/REPRODUCING.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/REPRODUCING.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/evidence/REPRODUCING.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/REPRODUCING.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/evidence/final-gate-results.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/final-gate-results.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/evidence/final-gate-results.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/final-gate-results.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/evidence/input-capability-inventory.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/input-capability-inventory.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/evidence/input-capability-inventory.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/input-capability-inventory.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/evidence/production-isolation.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/production-isolation.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/evidence/production-isolation.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/production-isolation.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/evidence/value-semantics-contract.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/value-semantics-contract.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/evidence/value-semantics-contract.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/evidence/value-semantics-contract.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/proposal.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/proposal.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/proposal.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/proposal.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/specs/domain-web-components/spec.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/specs/domain-web-components/spec.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/specs/domain-web-components/spec.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/specs/domain-web-components/spec.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/specs/rich-graphql-value-semantics/spec.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/specs/rich-graphql-value-semantics/spec.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/specs/rich-graphql-value-semantics/spec.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/specs/rich-graphql-value-semantics/spec.md
diff --git a/openspec/changes/harden-webcomponent-input-value-semantics/tasks.md b/openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/tasks.md
similarity index 100%
rename from openspec/changes/harden-webcomponent-input-value-semantics/tasks.md
rename to openspec/changes/archive/2026-08-23-harden-webcomponent-input-value-semantics/tasks.md
diff --git a/openspec/specs/domain-web-components/spec.md b/openspec/specs/domain-web-components/spec.md
index 4ce2dd3ac26..df5f66d970e 100644
--- a/openspec/specs/domain-web-components/spec.md
+++ b/openspec/specs/domain-web-components/spec.md
@@ -790,3 +790,93 @@ Toolkit overlays, listeners, callbacks, and caches MUST remain subordinate to th
 - **WHEN** Causeway conversion or server validation rejects the selected reference value
 - **THEN** the semantic component presents the authoritative error and reconciles the internal control to the accepted pending state
 - **AND** the toolkit does not independently commit the rejected value
+
+### Requirement: Toolkit-neutral reversible value codecs
+The semantic editor registry SHALL select a toolkit-neutral value codec for every editable property and action parameter before selecting an internal control.
+A codec MUST preserve authoritative GraphQL values, control values, validation values, submitted variables, nullability, and error recovery without lossy implicit conversion.
+
+#### Scenario: Exact numeric value is edited
+- **WHEN** a `Long`, `BigInteger`, or `BigDecimal` value is rendered, edited, validated, and submitted
+- **THEN** its sign, digits, decimal scale, and accepted lexical precision are preserved without conversion through JavaScript `Number`
+- **AND** cancellation or rejection restores or retains the exact prior or pending lexical value as applicable
+
+#### Scenario: Toolkit implementation changes
+- **WHEN** a native control or qualified toolkit adapter edits the same advertised input
+- **THEN** both controls use the same codec and submit the same semantic GraphQL value
+- **AND** the public Causeway element and semantic event contract remain unchanged
+
+#### Scenario: No reversible codec exists
+- **WHEN** an advertised input shape has no registered reversible codec
+- **THEN** the component renders a Causeway-owned bounded unsupported state
+- **AND** does not submit a raw string, display formatter output, or partially converted value
+
+### Requirement: Null-preserving boolean editing
+The component library SHALL distinguish nullable Boolean `null`, `true`, and `false` throughout defaults, editing, validation, submission, reconciliation, and cancellation.
+A required Boolean MAY use a two-state control only when `null` is not a valid semantic value.
+
+#### Scenario: Nullable Boolean remains null
+- **WHEN** an optional Boolean has authoritative or default value `null` and the user submits without selecting true or false
+- **THEN** validation and invocation receive `null`
+- **AND** the control does not silently convert it to `false`
+
+#### Scenario: Nullable Boolean is changed
+- **WHEN** the user explicitly selects true, false, or no value
+- **THEN** the corresponding `true`, `false`, or `null` value is submitted exactly
+- **AND** a later authoritative refresh renders that same state
+
+### Requirement: Type-specific temporal editing
+The component library SHALL support each accepted GraphQL temporal input through a type-specific reversible codec.
+Local, offset, and named-zone values MUST preserve their respective date, time, offset, zone identifier, and accepted fractional precision without implicit browser-timezone conversion.
+
+#### Scenario: Local temporal value is edited
+- **WHEN** a local date, local time, or local date-time value is edited
+- **THEN** the submitted value preserves its local semantics and accepted fractional precision
+- **AND** no UTC offset or browser timezone is added implicitly
+
+#### Scenario: Offset or zoned value is edited
+- **WHEN** an offset date-time, offset time, or zoned date-time value is edited
+- **THEN** the codec validates and preserves the advertised offset or zone representation
+- **AND** a control incapable of preserving that information is not selected
+
+#### Scenario: Temporal value is malformed
+- **WHEN** the pending lexical value violates the advertised temporal grammar
+- **THEN** local validation prevents invocation and presents a field-specific error
+- **AND** the pending value remains available for correction
+
+### Requirement: Protected and resource input capability enforcement
+Semantic editors SHALL enable URL, password or protected-value, Blob, Clob, and local-resource input only when public metadata advertises a reversible authorized strategy and all required constraints.
+Display-only or undisclosed representations MUST NOT become editable through generic string fallback.
+
+#### Scenario: Protected value is write-only
+- **WHEN** an authorized member advertises a write-only protected input
+- **THEN** the editor permits a new value without revealing the prior value
+- **AND** automation, errors, events, and reconciliation do not expose the submitted secret
+
+#### Scenario: Resource constraints are complete
+- **WHEN** a resource input advertises accepted media, size, and representation constraints
+- **THEN** the editor enforces those constraints before GraphQL submission
+- **AND** submits only the public resource representation
+
+#### Scenario: Resource capability is incomplete
+- **WHEN** required authorization, media, size, path, or open-strategy metadata is absent
+- **THEN** the editor remains visibly unsupported or read-only
+- **AND** no file bytes, characters, path, or URL are submitted speculatively
+
+### Requirement: Authoritative value reconciliation
+Property and action interaction flows SHALL keep pending codec values separate from authoritative object state.
+Only successful server results may replace authoritative state, and obsolete, cancelled, disconnected, or route-replaced work MUST NOT overwrite newer state.
+
+#### Scenario: Validation rejects an exact pending value
+- **WHEN** local or GraphQL validation rejects a pending exact, temporal, nullable, protected, resource, or custom value
+- **THEN** the editor remains open with a safe representation of the pending value and mapped error
+- **AND** the last authoritative value remains unchanged
+
+#### Scenario: Mutation succeeds
+- **WHEN** the codec value is accepted and mutation succeeds
+- **THEN** the owning context reconciles from authoritative server data
+- **AND** display formatting does not reuse a stale control value
+
+#### Scenario: Pending work becomes obsolete
+- **WHEN** a newer edit, cancellation, disconnect, or route replacement supersedes validation or mutation work
+- **THEN** the obsolete result is ignored or aborted
+- **AND** no stale value or protected input leaks into the current component state
diff --git a/openspec/specs/rich-graphql-value-semantics/spec.md b/openspec/specs/rich-graphql-value-semantics/spec.md
index ba2be21739a..6e0e32a290c 100644
--- a/openspec/specs/rich-graphql-value-semantics/spec.md
+++ b/openspec/specs/rich-graphql-value-semantics/spec.md
@@ -130,3 +130,92 @@ Changes to generic fallback behavior SHALL include compatibility diagnostics and
 - **WHEN** strict output enforcement detects a logical type without an explicit strategy
 - **THEN** the application receives an actionable registration path
 - **AND** any temporary legacy string behavior requires explicit configuration
+
+### Requirement: Advertised scalar and runtime value agreement
+For every input capability advertised by rich GraphQL, the runtime SHALL unmarshal the accepted GraphQL representation into the declared domain Java value type before validation or invocation.
+The schema and runtime MUST reject malformed input consistently and MUST NOT advertise a scalar representation that reaches domain invocation as an incompatible raw value.
+
+#### Scenario: Advertised exact numeric string is submitted
+- **WHEN** introspection advertises a string input for `Long`, `BigInteger`, or `BigDecimal` and a client submits a valid canonical string
+- **THEN** validation and invocation receive the corresponding exact Java numeric type
+- **AND** no intermediate binary floating-point conversion changes the value
+
+#### Scenario: Advertised temporal scalar is submitted
+- **WHEN** a client submits a valid value through the temporal scalar advertised by introspection
+- **THEN** validation and invocation receive the declared local, offset, or zoned Java temporal type
+- **AND** its documented offset, zone, and precision semantics are preserved
+
+#### Scenario: Runtime conversion cannot satisfy the declaration
+- **WHEN** the accepted GraphQL representation cannot be converted to the declared domain type
+- **THEN** GraphQL returns a bounded input or validation error before domain invocation
+- **AND** does not expose implementation exceptions or invoke with an incompatible value
+
+### Requirement: Canonical exact numeric input contract
+Rich GraphQL SHALL define and enforce canonical lexical input contracts for `Long`, `BigInteger`, and `BigDecimal` that preserve every accepted domain value.
+The contract MUST state sign, digit, decimal, exponent, scale, range, and null behavior for each type.
+
+#### Scenario: Boundary integer is submitted
+- **WHEN** a client submits an accepted `Long` or `BigInteger` boundary outside JavaScript's safe integer range
+- **THEN** GraphQL round-trips the exact integer without digit loss
+- **AND** the domain receives the exact declared integer type
+
+#### Scenario: Precision-sensitive decimal is submitted
+- **WHEN** a client submits a decimal with significant trailing zeros or precision beyond binary floating point
+- **THEN** GraphQL preserves the accepted lexical scale and exact decimal value through validation and invocation
+- **AND** authoritative output follows the documented normalization policy
+
+#### Scenario: Exact numeric input is malformed
+- **WHEN** a numeric lexical value violates the declared grammar or range
+- **THEN** GraphQL rejects it with a bounded input error
+- **AND** no truncated, rounded, overflowed, or partially parsed value reaches domain code
+
+### Requirement: Complete temporal input catalogue
+Rich GraphQL SHALL advertise a reversible input contract for every built-in temporal type classified as input-capable.
+The contract MUST distinguish local values, offset-bearing values, named-zone values, legacy values, and configured formats.
+
+#### Scenario: Offset is significant
+- **WHEN** an offset-bearing value is submitted
+- **THEN** GraphQL preserves the submitted instant and offset according to the advertised scalar contract
+- **AND** does not replace the offset with the server or client default timezone
+
+#### Scenario: Zone identifier is significant
+- **WHEN** a named-zone value is submitted
+- **THEN** GraphQL preserves or deterministically normalizes both the instant and zone identifier according to the advertised format
+- **AND** rejects a value that omits required zone information
+
+#### Scenario: Temporal precision is significant
+- **WHEN** a temporal value contains accepted fractional seconds
+- **THEN** GraphQL preserves that precision through unmarshalling, validation, invocation, and authoritative output
+
+### Requirement: Nullable and protected input contract
+Rich GraphQL SHALL preserve nullable Boolean `null` independently from `false` and SHALL expose protected values only through explicitly authorized input capabilities.
+Protected output and errors MUST remain undisclosed.
+
+#### Scenario: Nullable Boolean is submitted
+- **WHEN** the declared Boolean input is nullable and the client submits `null`
+- **THEN** domain validation and invocation receive `null`
+- **AND** no default coercion changes it to `false`
+
+#### Scenario: Protected input is submitted
+- **WHEN** an authorized write-only protected input receives a new value
+- **THEN** GraphQL invokes the declared member without returning the prior or submitted secret
+- **AND** validation and error payloads contain only safe bounded messages
+
+### Requirement: Reversible resource and custom input strategies
+Rich GraphQL SHALL advertise Blob, Clob, URL, local-resource, and custom-value input only when a registered strategy can reconstruct the declared domain value under the public authorization, media, size, and representation constraints.
+Output formatting alone MUST NOT imply input capability.
+
+#### Scenario: Resource input satisfies its contract
+- **WHEN** an authorized client submits a resource value within advertised media and size constraints
+- **THEN** GraphQL reconstructs the declared resource domain type and invokes the member
+- **AND** authoritative output uses the existing safe resource-link policy
+
+#### Scenario: Custom reversible strategy is registered
+- **WHEN** a custom value strategy explicitly supports reversible input and the client submits its advertised representation
+- **THEN** GraphQL reconstructs the declared custom domain type before invocation
+- **AND** the strategy's bounded validation errors are preserved
+
+#### Scenario: Input strategy is absent
+- **WHEN** a resource or custom value has output behavior but no reversible input strategy
+- **THEN** schema construction or capability discovery marks it output-only or unsupported
+- **AND** GraphQL never passes generic map, string, byte, or character data to the domain member speculatively