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/09/01 16:16:58 UTC

(causeway) 04/07: docs(openspec): plan parameter temporal range constraints

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 ac62da366fa407d1000c99be63706fafecc1bd3d
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Sep 1 16:32:09 2026 +0200

    docs(openspec): plan parameter temporal range constraints
---
 .../.openspec.yaml                                 |  2 +
 .../design.md                                      | 84 ++++++++++++++++++++++
 .../proposal.md                                    | 30 ++++++++
 .../specs/domain-web-components/spec.md            | 55 ++++++++++++++
 .../generic-htmx-web-component-viewer/spec.md      | 30 ++++++++
 .../specs/vaadin-semantic-editor-families/spec.md  | 30 ++++++++
 .../tasks.md                                       | 29 ++++++++
 7 files changed, 260 insertions(+)

diff --git a/openspec/changes/add-parameter-temporal-range-constraints/.openspec.yaml b/openspec/changes/add-parameter-temporal-range-constraints/.openspec.yaml
new file mode 100644
index 00000000000..b4b3ece7847
--- /dev/null
+++ b/openspec/changes/add-parameter-temporal-range-constraints/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-01
diff --git a/openspec/changes/add-parameter-temporal-range-constraints/design.md b/openspec/changes/add-parameter-temporal-range-constraints/design.md
new file mode 100644
index 00000000000..7d1f6d149ee
--- /dev/null
+++ b/openspec/changes/add-parameter-temporal-range-constraints/design.md
@@ -0,0 +1,84 @@
+## Context
+
+The completed property-range work provides a shared immutable range model, ISO lexical validation, relative local-calendar resolution, precision-safe comparison, native attributes, and Vaadin host propagation.
+Action parameters already use the same editor registry and field adapters, but optional `<cw-parameter>` declarations currently carry only name, description, description presentation, and multiline hints.
+The interaction controller owns parameter defaults, choices, pending values, canonical preparation and validation, confirmation, invocation, cancellation, focus, and all prompt styles.
+The extension must therefore add local range behavior without moving authority into hidden declaration elements or application markup.
+
+## Goals / Non-Goals
+
+**Goals:**
+
+- Give `<cw-parameter>` optional `min` and `max` attributes and matching JavaScript properties.
+- Apply the existing `LocalDate`, `LocalTime`, and `LocalDateTime` absolute and relative grammar consistently with properties.
+- Resolve relative bounds once per prompt after canonical parameter types are known.
+- Prevent out-of-range parameter values from reaching GraphQL preparation, validation, confirmation, or invocation.
+- Preserve pending values, field-specific errors, focus, correction, cancellation, and all prompt styles.
+- Demonstrate future-date and daily office-hour constraints in Petclinic without raw Vaadin markup.
+
+**Non-Goals:**
+
+- Derive bounds from Causeway domain annotations or add GraphQL range metadata.
+- Let authored declarations create, remove, reorder, default, require, hide, disable, choose, validate canonically, or invoke parameters.
+- Treat a single `LocalDateTime` interval as a recurring daily office-hours rule.
+- Change offset, zoned, legacy, read-only, reference, or unsupported temporal behavior.
+
+## Decisions
+
+### Carry authored bounds through normalized parameter presentation
+
+`CausewayParameterElement` will observe `min` and `max`, expose matching properties, and include explicitly authored values in its normalized configuration.
+Normalization will preserve null versus blank and bound untrusted declaration text, but it will not parse the values because the declaration does not own the authoritative parameter datatype.
+The existing direct-child matching by authoritative parameter ID remains the only association mechanism.
+
+An alternative was to let `<cw-parameter>` resolve its own range, but that hidden presentation element has neither canonical type metadata nor prompt-generation ownership.
+
+### Resolve immutable ranges in the interaction controller
+
+After action preparation and default recomputation establish the canonical parameter list, the interaction controller will match declarations, normalize semantic type names, and resolve one immutable range per applicable parameter.
+The resolved map remains unchanged for the complete prompt generation, including recomputation, validation, confirmation, correction, and invocation.
+A later prompt opening resolves relative tokens again.
+
+An alternative was to resolve on every render, but `today`, `tomorrow`, or `now` could then drift while a prompt remains open.
+
+### Keep local range errors distinct from canonical parameter state
+
+Prompt state will retain local range errors separately from GraphQL-provided parameter validity.
+Committed edits and submission will check the frozen range before any GraphQL request.
+A local failure records the pending value, marks the parameter as validated, renders a field-specific reason, focuses the first invalid control on submission, and leaves canonical state untouched.
+Correction clears the local reason and resumes the existing preparation and validation lifecycle.
+
+An alternative was to overwrite `parameter.state.error`, but that risks confusing authored local failures with authoritative supporting-method results during recomputation.
+
+### Reuse editor context and adapter propagation
+
+A valid resolved range contributes `min` and `max` to the existing parameter editor context.
+The existing native temporal editor and semantic Vaadin field host already consume those fields, so parameter support will not duplicate toolkit logic.
+Absent, invalid, or inapplicable ranges contribute no bounds.
+The rendered parameter wrapper will expose `data-causeway-temporal-range-status="valid"` or `"invalid"` only while the prompt is active.
+
+### Split Petclinic booking date and time
+
+Petclinic `bookVisit` will replace its single `LocalDateTime visitAt` input with authoritative `LocalDate visitDate` and `LocalTime visitTime` inputs and combine them into the existing persisted `LocalDateTime`.
+The declaration will use `min="tomorrow"` for the date and `min="08:00" max="17:00"` for the time.
+Canonical Java validators will independently enforce a future calendar date and the inclusive office-hour interval.
+
+A single `LocalDateTime` minimum and maximum was rejected because one closed interval cannot express recurring office hours across every future day.
+
+## Risks / Trade-offs
+
+- [Risk] Parameter recomputation may replace canonical parameter state after a local correction. → Keep ranges and local errors in controller-owned prompt state keyed by stable authoritative IDs.
+- [Risk] Browser controls can flag a bound violation before Causeway commits the value. → Retain Causeway validation as the request gate and use toolkit validity only as complementary presentation.
+- [Risk] Relative bounds can cross midnight while a prompt is open. → Resolve once by design and document that reopening starts a new range generation.
+- [Risk] Refactoring Petclinic parameters changes generated GraphQL argument names. → Update all sample tests and preserve the persisted visit representation and action outcome.
+- [Risk] Authored invalid ranges could make prompts unusable. → Ignore the complete interval atomically and expose a deterministic diagnostic state.
+
+## Migration Plan
+
+No migration is required for existing declarations because omitted bounds normalize to null and preserve current behavior.
+Applications can add bounds incrementally to direct child `<cw-parameter>` declarations.
+Rollback consists of removing the attributes and reverting the Foundation controller/configuration changes; no stored data or GraphQL schema migration is involved.
+
+## Open Questions
+
+None.
diff --git a/openspec/changes/add-parameter-temporal-range-constraints/proposal.md b/openspec/changes/add-parameter-temporal-range-constraints/proposal.md
new file mode 100644
index 00000000000..5e9d0397914
--- /dev/null
+++ b/openspec/changes/add-parameter-temporal-range-constraints/proposal.md
@@ -0,0 +1,30 @@
+## Why
+
+Action prompts currently cannot apply the same declarative local-temporal bounds that editable properties support, so authored pages must rely on canonical validation alone even when date and time controls could prevent or explain invalid input earlier.
+Extending optional `<cw-parameter>` declarations closes that consistency gap and lets Petclinic demonstrate future-date and office-hour booking constraints without exposing Vaadin APIs.
+
+## What Changes
+
+- Add optional `min` and `max` attributes and JavaScript properties to `<cw-parameter>` declarations.
+- Reuse the existing local date, time, and date-time range grammar, relative-token resolution, precision-safe comparison, invalid-range fallback, and native/Vaadin propagation.
+- Resolve each declared range once when its action prompt begins and keep the result stable through validation, confirmation, correction, cancellation, and invocation.
+- Reject out-of-range pending parameter values locally before canonical GraphQL preparation, action validation, or invocation while retaining values for correction.
+- Keep undeclared parameters and non-local-temporal parameters unchanged, and preserve GraphQL authority over order, defaults, choices, required state, validation, confirmation, and invocation.
+- Refactor Petclinic `bookVisit` presentation and action parameters into a future `LocalDate` and office-hours `LocalTime`, then combine them into the existing authoritative `LocalDateTime` visit value.
+
+## Capabilities
+
+### New Capabilities
+
+None.
+
+### Modified Capabilities
+
+- `domain-web-components`: Extend optional `<cw-parameter>` presentation declarations with non-authoritative local-temporal range constraints and prompt-lifecycle validation behavior.
+- `generic-htmx-web-component-viewer`: Demonstrate future-date and office-hour parameter bounds through Petclinic `bookVisit` under native and Vaadin toolkit policies.
+- `vaadin-semantic-editor-families`: Propagate resolved parameter bounds to qualified local-temporal controls without changing application markup or adapter ownership.
+
+## Impact
+
+The change affects Foundation parameter configuration, action prompt state and validation, shared temporal editor contexts, Foundation tests and documentation, Vaadin field audits where needed, and the Petclinic `bookVisit` domain action, page declaration, integration tests, and Playwright acceptance.
+It introduces no GraphQL schema field, third-party dependency, or breaking public element rename.
diff --git a/openspec/changes/add-parameter-temporal-range-constraints/specs/domain-web-components/spec.md b/openspec/changes/add-parameter-temporal-range-constraints/specs/domain-web-components/spec.md
new file mode 100644
index 00000000000..7bba389b93a
--- /dev/null
+++ b/openspec/changes/add-parameter-temporal-range-constraints/specs/domain-web-components/spec.md
@@ -0,0 +1,55 @@
+## ADDED Requirements
+
+### Requirement: Declarative local-temporal action-parameter ranges
+An optional direct-child `<cw-parameter>` declaration SHALL accept `min` and `max` attributes and properties for authoritative `LocalDate`, `LocalTime`, and `LocalDateTime` action parameters.
+Valid bounds MUST constrain the presented editor and Causeway-owned prompt validation without changing authoritative parameter existence, order, type, defaults, choices, required state, visibility, disabled state, canonical validation, confirmation, or invocation.
+
+#### Scenario: Absolute local-date parameter interval is authored
+- **WHEN** a declared authoritative `LocalDate` parameter has valid ascending ISO `min` and `max` bounds
+- **THEN** its native or qualified editor exposes the closed date interval
+- **AND** values equal to either boundary remain admissible
+
+#### Scenario: Office-hour parameter interval is authored
+- **WHEN** a declared authoritative `LocalTime` parameter has `min="08:00"` and `max="17:00"`
+- **THEN** its editor exposes that closed time interval while retaining the supported quarter-hour picker choices
+- **AND** accepted pending seconds, fractional seconds, and off-quarter-hour minutes remain unchanged until explicitly edited
+
+#### Scenario: Local date-time parameter interval is authored
+- **WHEN** a declared authoritative `LocalDateTime` parameter has compatible absolute ISO bounds
+- **THEN** its editor receives matching local date-time bounds without UTC conversion
+- **AND** comparison uses local calendar and clock parts
+
+#### Scenario: Relative parameter bound begins a prompt
+- **WHEN** `today` or `tomorrow` is declared for a `LocalDate`, or `now` is declared for a `LocalDateTime`, and the action prompt begins
+- **THEN** the token resolves once from the browser's current local calendar or clock after the authoritative datatype is known
+- **AND** the resolved boundary remains stable for that prompt generation and resolves again for a later opening
+
+#### Scenario: Pending parameter lies outside its range
+- **WHEN** a well-formed pending local-temporal parameter value compares outside its resolved closed interval
+- **THEN** the prompt retains the pending value and presents a field-specific correction naming the violated boundary
+- **AND** no GraphQL preparation, action validation, confirmation, or invocation request is issued for that attempt
+
+#### Scenario: Pending parameter is corrected
+- **WHEN** the user corrects the pending value into the resolved interval
+- **THEN** the local range reason clears and canonical preparation and action validation resume
+- **AND** canonical domain validation can still reject the value independently
+
+#### Scenario: Prompt submission finds an out-of-range value
+- **WHEN** submission occurs before a bounded parameter has committed a valid in-range value
+- **THEN** submission fails locally and focus moves through the existing first-invalid-control lifecycle
+- **AND** the prompt remains open with all pending values available for correction or cancellation
+
+#### Scenario: Authored parameter interval is unusable
+- **WHEN** either bound is blank, malformed, incompatible with the authoritative datatype, or resolves below the minimum
+- **THEN** the entire authored interval is ignored and the canonical parameter editor remains usable
+- **AND** the rendered parameter exposes a deterministic invalid-range diagnostic hook without fabricating a bound
+
+#### Scenario: Parameter is undeclared or inapplicable
+- **WHEN** no matching declaration exists, or `min` or `max` is declared for a non-local, offset, zoned, legacy, reference, or unsupported parameter
+- **THEN** editor selection, parsing, validation, defaults, choices, and GraphQL behavior remain unchanged
+- **AND** declaration data cannot create, remove, or reorder an authoritative parameter
+
+#### Scenario: Prompt is cancelled or reopened
+- **WHEN** a bounded prompt is cancelled and later reopened
+- **THEN** cancellation uses the existing focus-restoration lifecycle without invoking the action
+- **AND** the new prompt resolves a fresh immutable range from its own start time
diff --git a/openspec/changes/add-parameter-temporal-range-constraints/specs/generic-htmx-web-component-viewer/spec.md b/openspec/changes/add-parameter-temporal-range-constraints/specs/generic-htmx-web-component-viewer/spec.md
new file mode 100644
index 00000000000..661e0d9d2bd
--- /dev/null
+++ b/openspec/changes/add-parameter-temporal-range-constraints/specs/generic-htmx-web-component-viewer/spec.md
@@ -0,0 +1,30 @@
+## ADDED Requirements
+
+### Requirement: Petclinic bounded visit parameter qualification
+The Petclinic owner page SHALL demonstrate declarative action-parameter ranges by booking visits with a future `LocalDate` and an inclusive office-hours `LocalTime` through direct-child `<cw-parameter>` declarations.
+The domain action MUST combine accepted date and time values into the existing authoritative visit date-time and retain canonical validation for both constraints.
+
+#### Scenario: Book Visit prompt opens
+- **WHEN** browser acceptance opens `bookVisit`
+- **THEN** the date editor exposes the resolved `tomorrow` minimum and the time editor exposes `08:00` and `17:00` bounds
+- **AND** defaults, parameter order, labels, prompt style, picker accessibility, and cancellation remain authoritative or presentation-driven as before
+
+#### Scenario: Non-future visit date is attempted
+- **WHEN** the user enters a date before the resolved future-date minimum
+- **THEN** the prompt retains the date and presents a local minimum reason
+- **AND** no `bookVisit` GraphQL preparation, validation, or mutation request occurs for the rejected attempt
+
+#### Scenario: Time outside office hours is attempted
+- **WHEN** the user enters a well-formed time before `08:00` or after `17:00`
+- **THEN** the prompt retains the time and presents the matching local boundary reason
+- **AND** no `bookVisit` GraphQL preparation, validation, or mutation request occurs for the rejected attempt
+
+#### Scenario: Visit date and time are corrected
+- **WHEN** both pending values lie within their declared ranges
+- **THEN** canonical action validation and one `bookVisit` mutation proceed
+- **AND** the refreshed visit collection exposes the combined authoritative local date-time
+
+#### Scenario: Native and Vaadin policies are exercised
+- **WHEN** Petclinic runs under the default Vaadin and explicit native component-toolkit policies
+- **THEN** both date and time controls receive equivalent bounds and local request gating
+- **AND** Petclinic markup contains only public Causeway elements and attributes
diff --git a/openspec/changes/add-parameter-temporal-range-constraints/specs/vaadin-semantic-editor-families/spec.md b/openspec/changes/add-parameter-temporal-range-constraints/specs/vaadin-semantic-editor-families/spec.md
new file mode 100644
index 00000000000..7aba79d63c0
--- /dev/null
+++ b/openspec/changes/add-parameter-temporal-range-constraints/specs/vaadin-semantic-editor-families/spec.md
@@ -0,0 +1,30 @@
+## ADDED Requirements
+
+### Requirement: Qualified action-parameter temporal range propagation
+The qualified Vaadin local-temporal adapter SHALL consume Causeway-resolved `min` and `max` values from action-parameter editor contexts for editable date-picker, time-picker, and date-time-picker controls.
+Causeway SHALL remain authoritative for declaration matching, interval normalization, local request gating, pending values, canonical validation, and invocation.
+
+#### Scenario: Parameter date picker receives bounds
+- **WHEN** an eligible `LocalDate` action parameter carries a valid resolved interval
+- **THEN** the internal date picker receives matching ISO bounds before its pending or default value
+- **AND** calendar choices outside the interval follow the toolkit's supported disabled-range behavior
+
+#### Scenario: Parameter time picker receives office hours
+- **WHEN** an eligible `LocalTime` action parameter carries `08:00` and `17:00` bounds
+- **THEN** the internal time picker receives both bounds and retains the established 15-minute dropdown step
+- **AND** its labelled clock trigger, synchronous keyboard activation, clear control, and focus behavior remain unchanged
+
+#### Scenario: Parameter date-time picker receives bounds
+- **WHEN** an eligible `LocalDateTime` action parameter carries a valid resolved interval
+- **THEN** the internal date-time picker receives matching local ISO bounds without timezone conversion
+- **AND** its composed date and time controls retain accessible names and triggers
+
+#### Scenario: Parameter range is absent or invalid
+- **WHEN** the action-parameter editor context carries no valid resolved interval
+- **THEN** the internal Vaadin control receives no minimum or maximum
+- **AND** qualification, native fallback, default value, required state, disabled state, and prompt lifecycle remain unchanged
+
+#### Scenario: Bounded parameter prompt is cancelled
+- **WHEN** a qualified bounded parameter editor is cancelled without invocation
+- **THEN** its overlay, clear control, pending state, and focus are disposed through the existing prompt lifecycle
+- **AND** reopening installs controls with newly resolved bounds and no stale adapter state
diff --git a/openspec/changes/add-parameter-temporal-range-constraints/tasks.md b/openspec/changes/add-parameter-temporal-range-constraints/tasks.md
new file mode 100644
index 00000000000..c356e633bc1
--- /dev/null
+++ b/openspec/changes/add-parameter-temporal-range-constraints/tasks.md
@@ -0,0 +1,29 @@
+## 1. Parameter declaration contract
+
+- [ ] 1.1 Add observed `min` and `max` attributes and matching JavaScript properties to `<cw-parameter>`.
+- [ ] 1.2 Preserve explicit null-versus-blank bounds through bounded normalized parameter configuration.
+- [ ] 1.3 Propagate bounds through direct-child capture, action presentation, rerendering, and declaration-order deduplication.
+- [ ] 1.4 Add unit coverage for attributes, properties, configuration events, normalization, late declarations, and undeclared parameters.
+
+## 2. Prompt range lifecycle and request gating
+
+- [ ] 2.1 Resolve immutable parameter ranges after canonical preparation and default recomputation using authoritative semantic types.
+- [ ] 2.2 Retain resolved ranges and separate local range errors in generation-safe prompt state across recomputation and rendering.
+- [ ] 2.3 Add valid bounds and deterministic valid or invalid status hooks to rendered parameter editor contexts and wrappers.
+- [ ] 2.4 Reject committed out-of-range values before GraphQL preparation while retaining pending values, local reasons, and focus.
+- [ ] 2.5 Reject out-of-range submission before GraphQL preparation, action validation, confirmation, or invocation and focus the first invalid control.
+- [ ] 2.6 Clear local reasons on correction and preserve canonical preparation, validation, confirmation, invocation, cancellation, and reopening.
+- [ ] 2.7 Add controller tests for absolute and relative bounds, precision, invalid intervals, non-temporal isolation, no-request rejection, correction, submission, and cancellation.
+
+## 3. Native and qualified temporal editors
+
+- [ ] 3.1 Verify parameter editor contexts reuse the existing native temporal `min` and `max` attributes without adapter-specific markup.
+- [ ] 3.2 Verify qualified date, time, and date-time parameter controls receive bounds before values while preserving steps, triggers, clear controls, and fallback.
+- [ ] 3.3 Extend Foundation and browser coverage for Vaadin and native parameter range behavior and diagnostic cleanliness.
+
+## 4. Petclinic demonstration and validation
+
+- [ ] 4.1 Refactor `bookVisit` to accept a future `LocalDate` and inclusive office-hours `LocalTime`, combine them into the persisted `LocalDateTime`, and retain canonical validators.
+- [ ] 4.2 Declare `min="tomorrow"` for `visitDate` and `min="08:00" max="17:00"` for `visitTime` through nested `<cw-parameter>` elements.
+- [ ] 4.3 Extend Petclinic integration and Playwright coverage for bounds, local no-request rejection, correction, invocation, cancellation, picker accessibility, and both toolkit policies.
+- [ ] 4.4 Update Foundation usage and component contract documentation, run complete Foundation Node and Maven suites, Vaadin audits, Petclinic tests, IDE validation, strict OpenSpec validation, and final diff checks.