Skip to content

Commit 062ae7d

Browse files
namedgraphclaude
andcommitted
A package keeps taking effect on the next request, instead of twenty seconds later.
The previous commit made server-side composition wait for the compiled client stylesheet, so that a package could never be live on one renderer and not the other. That broke misc/PATCH-settings-package-import.sh, which declares an ldh:import and asserts the package's marker on the very next response - and the test is right. Its own comment, and the 5.10.0 changelog that introduced declarative imports, state the contract: effective on the next request, no restart. Holding the server back silently converted that into "effective in about twenty seconds", which is a different product. The second consequence was worse than the interleaving it was meant to prevent. The Dockerfile always sets SEF_COMPILER, so the service is always constructed and the "no compiler configured" fallback never fires in a real deployment - an instance whose compiler container was missing or unreachable would have lost package rendering entirely rather than degrading to the behaviour it had before any of this existed. So composition is never withheld. Packages compose server-side on every request, exactly as they did; the compiled SEF is an addition the client picks up once it exists. The window where the server has the package and the client does not is precisely the behaviour that shipped in 5.10.0 and has been permanent ever since - it is now bounded to one compile after an install or a platform upgrade, which is the improvement this branch is for. One thing this costs, recorded because it is a real change in observability: a compile failure is no longer visible in the rendered page, since the server still composes. It surfaces in the build's exceptionally handler and in the compiler's verbatim stderr, and nowhere else. Known and not addressed here: while a key is unpublished, every render submits a build. computeIfAbsent deduplicates concurrent ones, but a failing compiler clears the entry on completion, so a persistently unreachable compiler means one attempt per request. Cheap to bound with a negative cache; out of scope for restoring the contract. Verified: mvn compile clean. The assertion sequence the test drives now holds by construction - no import, stock; import, composed on the next request; import removed, stock again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSRUJBNKKjdgJeP3qRZTPd
1 parent 918d565 commit 062ae7d

1 file changed

Lines changed: 11 additions & 16 deletions

File tree

‎src/main/java/com/atomgraph/linkeddatahub/server/filter/response/XsltExecutableFilter.java‎

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,26 +103,21 @@ public void filter(ContainerRequestContext req, ContainerResponseContext resp) t
103103
ClientStylesheetService stylesheetService = getSystem().getClientStylesheetService();
104104

105105
if (packages.isEmpty()) req.setProperty(AC.stylesheet.getURI(), getXsltExecutable(stylesheet));
106-
else if (stylesheetService == null)
107-
// no compiler configured: compose server-side only, which is how packages behaved
108-
// before client-side composition existed
109-
req.setProperty(AC.stylesheet.getURI(), getXsltExecutable(getApplication().get(), stylesheet, packages));
110106
else
111107
{
112-
String key = stylesheetService.getKey(packages);
108+
// server-side composition is never withheld: a declarative import takes effect on the
109+
// next request, and it is the only rendering an instance whose compiler is unreachable
110+
// will ever get
111+
req.setProperty(AC.stylesheet.getURI(), getXsltExecutable(getApplication().get(), stylesheet, packages));
113112

114-
if (stylesheetService.isPublished(key))
113+
if (stylesheetService != null)
115114
{
116-
req.setProperty(LDH.clientStylesheet.getURI(), stylesheetService.getPublicPath(key));
117-
req.setProperty(AC.stylesheet.getURI(), getXsltExecutable(getApplication().get(), stylesheet, packages));
118-
}
119-
else
120-
{
121-
// both renderers stay on the uncomposed stylesheet until the compiled one exists.
122-
// Composing server-side while the client cannot is what makes a package's rules
123-
// appear on load and vanish on the first client-side navigation
124-
stylesheetService.buildAsync(key, getStylesheets(packages));
125-
req.setProperty(AC.stylesheet.getURI(), getXsltExecutable(stylesheet));
115+
String key = stylesheetService.getKey(packages);
116+
117+
// until the composed stylesheet exists the client renders without the package, as it
118+
// always has; compiling one closes that window rather than opening it
119+
if (stylesheetService.isPublished(key)) req.setProperty(LDH.clientStylesheet.getURI(), stylesheetService.getPublicPath(key));
120+
else stylesheetService.buildAsync(key, getStylesheets(packages));
126121
}
127122
}
128123
}

0 commit comments

Comments
 (0)