Validate preview sessions against real classpath and module-path fixtures

This commit is contained in:
2026-11-12 09:47:59 +01:00
parent e97af99412
commit 28c1e47c95
52 changed files with 1867 additions and 9 deletions
+2
View File
@@ -100,6 +100,8 @@ FXML previews overlay the owning host's current parent and open Component drafts
## Discovery and preview API
Work package 6 now qualifies the [development API and target adapter](preview-target-fixtures.md) against real classpath/module-path fixtures. Session cleanup is cooperative; a fresh target JVM is required to release NeitzelLib process-wide Model/ViewModel state.
Metadata listing must not construct Models or invoke Controller methods. Separate example descriptors (stable IDs, display labels, compatible Model/View information and declared capabilities) from runtime construction. Generated descriptor metadata or equivalent non-constructing discovery must be tested; calling arbitrary provider initialization merely to list examples does not satisfy this boundary.
Selecting an example creates a fresh owned preview session with its Model graph and explicitly configured services. Provide readiness and cleanup hooks. Ordinary examples become ready after load/CSS/layout; asynchronous examples signal readiness subject to cancellation/timeout. Construction, services, Controller actions and cleanup execute only in the target JVM. Verify the adapter against NeitzelLib's actual injection/loading lifecycle before publishing Java signatures.
+71
View File
@@ -0,0 +1,71 @@
# Preview API and target adapter qualification
Work package 6 is implemented against the [verified NeitzelLib development artifact](runtime/neitzellib-baseline.md), Java 21 and application JavaFX 21.0.7. This qualifies target-side execution; it does not connect the designer UI, snapshot activation or worker transport. Those remain work package 7.
## Discovery and construction
The dependency-free Java 21 preview API contains:
- `ExampleDescriptor(id, label, modelType, providerClass, viewResource, componentPackage)`.
- `PreviewProvider<M,C>`: `modelType()` and `open(exampleId)`.
- `PreviewSession<M,C>`: `model()`, `context()`, asynchronous `ready()` and `close()`.
The NeitzelLib target adapter requires an `ApplicationContext` context. Providers have public no-argument constructors. They create fresh Models and explicitly configured services after selection, on the target FX thread. They own cleanup of partial allocations when construction throws before returning a session. The adapter owns the returned session and calls its cleanup once on load failure, readiness failure, timeout, cancellation or normal close.
Discovery reads UTF-8 `META-INF/neitzel-fx-designer/examples.properties` resources without loading provider or Model classes. This development metadata contract has format version 1:
```properties
format=1
count=1
example.0.id=standard
example.0.label=Standard person
example.0.modelType=fixture.model.Person
example.0.providerClass=fixture.preview.Examples
example.0.viewResource=fixture/components/Person.fxml
example.0.componentPackage=fixture.components
```
Resources are classloader-relative. Catalogs reject unknown/missing/duplicate keys, duplicate IDs across resources, invalid UTF-8 and unsupported versions. Limits are 1 MiB per catalog, 128 catalogs, 1,024 total examples and 4,096 characters per descriptor field. Discovery returns immutable descriptors ordered by ID. No ServiceLoader factory is invoked to list examples.
After selection the adapter checks provider/Model compatibility, invokes NeitzelLib's real `ViewLoader`, creates a Scene and applies CSS/layout before asking for readiness. Readiness must never block FX. Rendering produces bounded row-major straight-alpha RGBA8 using the target's JavaFX. Structured failures distinguish module access, invalid Model/context/provider/resource, loading, readiness, cancellation, timeout and cleanup. Original exception causes remain available.
These are tested development signatures, not a published API release or a promise of compatibility with every NeitzelLib version.
## Lifecycle boundary established by the fixtures
NeitzelLib's `ViewModels` retains Model/ViewModel identities in a process-wide identity map with no public disposal operation. Closing a session releases provider-owned resources but cannot clear that map. Consequently `TargetPreview` allows **one session per target JVM**, including failed sessions. Every restart and interactive preview needs a fresh process.
The adapter's readiness deadline and cleanup are cooperative FX-thread operations. A blocked constructor, Controller or cleanup hook cannot be interrupted by the adapter. Work package 7 must enforce an external process deadline, bounded graceful shutdown and forced termination using the host-owned lifetime channel. The fixture runner enforces a 30-second process timeout. Session close is not proof that library-held objects have been garbage-collected.
## Classpath and module path
The [fixtures](../integration-fixtures/preview/) are ordinary Maven applications depending on artifacts, without copies of library source or Kit/IntelliJ dependencies:
- Classpath: application in main sources; provider, descriptors and executable checks in test sources.
- Module path: named application, separate named preview module and named check launcher. Application and preview dependencies are declared normally in Maven.
The preview API, contracts and target tools now publish stable `Automatic-Module-Name` manifest entries: `de.neitzel.fxdesigner.preview`, `de.neitzel.fxdesigner.contracts`, and `de.neitzel.fxdesigner.target`. They are automatic modules, not fully modularized libraries. The qualified NeitzelLib artifacts resolve as automatic modules `fx`, `injection` and `core`.
The fixture's Component/Controller package is unconditionally open for NeitzelLib's Reflections package discovery and FXML injection. The Model package opens to `fx` for bean binding access. The provider package exports to the target adapter and check launcher. See the actual fixture module descriptors for the complete requires/exports declarations. Removing either Component openness or Model openness produces a structured `MODULE_ACCESS` failure. No broad command-line `--add-opens` repairs are applied.
This qualifies the boot module layer and these packages, not arbitrary custom module layers or every application package topology.
## Reproduce and evidence
After installing the designer reactor and verified NeitzelLib artifact:
```sh
python3 scripts/check-preview-fixtures.py --target-java-home "$TARGET_JAVA_HOME"
```
The same suite runs from `scripts/check-bootstrap.py`. It builds temporary copies of both fixture reactors with Java 21 and launches 24 target processes, covering 346 assertions:
- Metadata discovery without provider initialization or Model/Controller construction.
- Constructor-injected Components, post-initialization custom attributes, inherited attribute coercion and invalid attributes.
- Named ViewModel selection, Controller handoff, configured services, parent and nested bindings, write-back, shared nested Model/ViewModel identity and distinct Component instances.
- Nonempty rendered images and image-size limits.
- Delayed readiness, timeout, cancellation, factory/load/readiness/cleanup failure and exactly-once cleanup.
- Fresh Models/services in separate JVMs and rejection of session reuse.
- Missing Component and Model module access.
Logs and machine-readable results go to `designer-target-tools/target/preview-fixtures/`. Unit tests additionally validate hostile/malformed metadata. The suite requires a graphical environment capable of initializing JavaFX; macOS is qualified here. It does not validate headless rendering, Windows/Linux packaging, real worker IPC or either host UI.
+3 -1
View File
@@ -1,6 +1,6 @@
# NeitzelFXDesigner repository bootstrap plan
Status: repository foundation implemented by the initial commit; work package 2 has a verified development artifact; work package 3 implements the module/service foundation; work package 4 implements configuration and protocol validation; work package 5 implements Build and Refresh with immutable snapshots; work packages 6–7 remain planned. Consolidated 2026-11-12. Scope is the ordered implementation start for the [accepted initial contract](initial-project-contract.md); the initial commit creates the foundation only and does not publish a library release.
Status: repository foundation implemented by the initial commit; work package 2 has a verified development artifact; work package 3 implements the module/service foundation; work package 4 implements configuration and protocol validation; work package 5 implements Build and Refresh with immutable snapshots; work package 6 validates the preview API and target adapter with real fixtures; work package 7 remains planned. Consolidated 2026-11-12. Scope is the ordered implementation start for the [accepted initial contract](initial-project-contract.md); the initial commit creates the foundation only and does not publish a library release.
## Starting-point evidence before bootstrap
@@ -74,6 +74,8 @@ Resolve scoped Maven builds, preview source arrangements, explicit save/cancel a
### 6. Validate the preview API and target adapter against real fixtures
Implemented: resource-only discovery, typed sessions, real NeitzelLib loading/rendering and 24 classpath/module-path process checks. See [qualification and lifecycle limits](preview-target-fixtures.md). Library-held Model/ViewModel state requires a fresh JVM per session; external shutdown enforcement remains work package 7.
Add classpath/module-path Maven fixture applications using NeitzelLib artifacts. Implement non-constructing descriptor discovery and typed provider/session lifecycle against the real library. Test fresh Models/services, readiness, cleanup, invalid attributes and write-back. Freeze public Java signatures only after these tests establish the adapter contract.
**Exit:** standalone target-side tests pass without Kit/IntelliJ dependencies leaking into application-facing artifacts; both preview source arrangements are represented.