Discover Model paths and compatible binding targets in both hosts

Add non-constructing target metadata and a shared read-only browser for the Person fixtures. Negotiate binding discovery independently, preserve FXML, and explain direction/type mismatches. Record remaining manual navigation checks as explicitly skipped.
This commit is contained in:
2026-11-13 08:57:35 +01:00
parent 2156894fa8
commit 2fe408bb4d
38 changed files with 1087 additions and 37 deletions
@@ -198,6 +198,30 @@ public final class DesignerWorkflow implements AutoCloseable {
return build.start(request, approved, line -> log.accept(line.line()));
}
public CompletionStage<BindingMetadata> bindings(
boolean last, DocumentSnapshot document, String path, String direction) {
return execute(
last,
List.of(document),
worker -> {
var result =
worker.request(
Operation.BINDINGS,
Map.of(document.document().toString(), document.revision()),
0,
0,
PreviewMessages.encode(
Map.of("fxml", document.text(), "path", path, "direction", direction)),
Duration.ofSeconds(15));
try (var current =
host.documents().open(document.document()).toCompletableFuture().get()) {
if (current.snapshot().toCompletableFuture().get().revision() != document.revision())
throw new CancellationException("Draft changed during discovery");
}
return BindingMetadata.decode(PreviewMessages.decode(result.payload()));
});
}
public CompletionStage<List<Example>> discover(boolean lastSuccessful) {
return discover(lastSuccessful, false, List.of());
}
@@ -104,7 +104,7 @@ public final class PreviewWorker implements AutoCloseable {
id,
process.pid(),
token,
Set.of("discover-v1", "render-rgba-v1", "layout-v1", "interactive-v1"),
Set.of("discover-v1", "render-rgba-v1", "layout-v1", "interactive-v1", "bindings-v1"),
config.requiredCapabilities());
}
drain(process.getInputStream(), log);
@@ -42,6 +42,28 @@ public final class ConnectedWorkflowContract {
try (var doc = await(host.documents().open(file.toUri()));
var component = await(host.documents().open(child.toUri()))) {
var initial = await(doc.snapshot());
var bindings = await(workflow.bindings(false, initial, "name", "both"));
check(
bindings.attributes().stream().anyMatch(a -> a.path().equals("home.street")),
"Nested Model path discovery");
check(
bindings.targets().stream()
.anyMatch(
t ->
t.control().equals("name")
&& t.property().equals("text")
&& t.status().equals("COMPATIBLE")),
"Compatible binding target discovery");
var complex = await(workflow.bindings(false, initial, "home", "both"));
check(
complex.targets().stream()
.anyMatch(
t ->
t.control().equals("card")
&& t.property().equals("model")
&& t.type().equals("fixture.model.Address")
&& t.status().equals("COMPATIBLE")),
"Component Model metadata compatibility");
var first = await(workflow.render(false, "standard", "card", 310, 220, List.of(initial)));
check(first.rgba().length == 310 * 220 * 4, "Image frame");
long firstPid = workflow.renderingPid();