Develop - #405
Merged
Merged
Develop#405
Conversation
The CLI resolves the library by ${project.version} from a remote repository,
which made every version transition wait on a publish landing first. The
post-release bump broke develop immediately: it asks for 6.0.2-SNAPSHOT, which
nothing deploys, and the release tag asks for 6.0.1, which Central has not seen.
Both HTTP-tests and UI-tests failed on dependency resolution while Load-tests,
which builds no CLI, stayed green.
The library is in the same checkout at the same commit, so the checkout is the
source of truth and the remote round-trip bought nothing but a failure mode. The
three workflows that build the CLI now install rdf/ first, which is what `make
cli` has always done locally - the gap was that CI does not use make, so
verifying through make left it invisible.
cli/pom.xml's snapshot repository goes with it. It is not merely unnecessary now
but harmful: with a remote fallback present, a build that lost the rdf step would
quietly resolve an older published snapshot instead of failing, and pass against
stale code. Verified both ways against throwaway local repositories - install
then package succeeds at 40 and 86 tests, package alone fails on the missing
artifact. Deploying rdf/ is now a REST-VKG concern only; nothing here resolves
the library remotely.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One multi-platform build on an amd64 runner emulated the arm64 leg through QEMU, so javac, the Saxon SEF compile and npm all ran at a fraction of native speed, serialized behind the amd64 leg. Split into one job per architecture on a runner of that architecture: each pushes an untagged manifest by digest, and a merge job assembles them into the tagged manifest lists with imagetools. The tags only move once both architectures are known good, so a failed release can no longer leave a partial multi-architecture manifest behind latest. Add the GitHub Actions layer cache, one scope per image and architecture. The SEF compiler build reads the platform scope as well, which is where the maven stage the two share is exported; a single shared scope would have them overwrite each other's export on every run. Resolve the dependency tree in a layer keyed on the POM alone, so a source change no longer invalidates it - it did before, because COPY src preceded COPY pom.xml and nothing between them depended on the POM by itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The last SPARQLBuilder calls in the client stylesheets were `SelectBuilder.fromString(s).build()` and `SelectBuilder.fromQuery(json).toString()`, which are SPARQL.js's `Parser` and `Generator` with nothing added: `fromString` constructs a bare Parser, `build()` returns the parse tree untouched and `toString()` is `Generator.stringify()`. The 22 sites now call the `$sparql-parser` and `$sparql-generator` params `client.xsl` already declares, as `ldh:parse-query` and `ldh:build-update` already did. `SPARQLBuilder.js` goes, and with it the second copy of SPARQL.js it bundled (330 KB off every page load). The flag that gated the two scripts in `layout.xsl` now gates the one it loads, and the comments that blamed the GRAPH-merging round-trip on SPARQLBuilder name the SPARQL.js round-trip the behaviour belongs to. Verified by compiling the client SEF (`make sef`); the browser specs were not run, the stack was down. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…r comes back as a 500 Jersey parses the header lazily, on every selectVariant() and getAcceptableLanguages() call, and every exception mapper builds its response through selectVariant(). A value such as "en-IN,en;q=0.9,en;q=0.9;q=0.8" therefore threw from inside the mapper, past Jersey's own 400 fallback, and the container answered 500 in place of the mapper's 403. The same header already gave an authorized request a bare 400 through the three direct readers (ResponseHeadersFilter, the graph store, the XSLT writer). The header is advisory, so the request proceeds as if the client stated no preference. The filter runs pre-matching, before anything that can fail into a mapper, and catches the JAX-RS ProcessingException rather than Jersey's internal HeaderValueException. Since the header is re-read from the live map each time, this one filter covers the LDH mappers, the Web-Client and Core mappers, and the direct readers alike. The test drives a real ContainerRequest, so it is Jersey's own parser that fails and the very call which used to throw that is asserted to succeed afterwards. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… ETag, so it no longer fails 412
Restore writes the chosen version back to the live document with If-Match, and quoted
whatever tag LinkedDataHub.contents held under the document's URI. Loading a ?version=
view stored the memento's own tag there - its commit SHA - which never matches the live
document, so a restore pressed after Compare, or from any version link, was refused 412
Precondition Failed ("This version could not be restored"). Pressed from the live document
it worked, which is why it went unnoticed since #392 made the write conditional.
A memento's tag is no longer stored as the document's, and the restore asks for its
validator through ldh:with-document-etag, which HEADs the live document when the browser
holds none. From the live document it still quotes the tag the page loaded with, so a
write made since the history was opened still refuses the restore.
tests/ui gains the memento spec: a document of its own, written three times, restored from
the live document and from a historical version, asserting the If-Match against the live
ETag. It skips where graph versioning is not configured.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… a dataspace changed at runtime The settings overlay held a copy of every dataspace changed at runtime, and that copy replaced the configured graph on load. config/dataspaces.trig and config/system.trig both write into the dataspace's graph, so the copy froze system.trig's wiring too: installing a package (PATCH /settings) and then enabling graph versioning left lds:versioningRepository dropped on every boot - no commits, ?timemap 404, no History link - with only "the configuration for it is not in effect" in the log. The same held for lds:service, the ontology, the stylesheet and anything else configured after the first runtime change. The overlay is now settings/dataspaces.ru, a SPARQL Update of DELETE DATA and INSERT DATA: the statements a runtime change removed from the configuration and the ones it added. Load applies it to the configuration as it is, so a removal stays removed - an uninstalled package does not come back - and a statement added to the configuration later takes effect. The graphs are copied before it is applied: the copy used to link them, and deleting from the live dataset would have deleted from the configured one. A copy-style dataspaces.trig is converted once and left in place. It cannot tell a statement removed at runtime from one added to the configuration since, so the latter carries over as removed. Blank nodes cannot be matched across a restart; removing a statement that has one is logged and not persisted. The tests had encoded the replacement - an edit reaching an untouched dataspace was the only case. New ones cover an edit reaching a changed dataspace, a removal staying removed, the configuration left alone by a load, and the legacy conversion. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ss that keeps an empty fragment The platform's own Link wrote the relation type unquoted - rel=http://www.w3.org/ns/auth/acl#mode - which RFC 8288 does not allow: ':', '/' and '#' are not token characters, so a URI relation type has to be quoted. It could carry no parameter beyond rel and type, and Core's Link.valueOf, which XSLTWriterBase parsed with, kept the quotes in the value it returned. Jersey's implementation of jakarta.ws.rs.core.Link cannot stand in for it as it is: it holds the target in a UriBuilder, which drops an empty fragment whether the link is built or parsed, so https://localhost:4443/ns# - every dataspace's lds:ontology - came out as https://localhost:4443/ns, a different URI. server.util.Link now extends jakarta's Link and stores the URI as given, with a builder shaped like Jersey's. Serialization is Jersey's header delegate, which writes from getUri() and so writes the fragment; valueOf takes the target from between the angle brackets and lets Jersey parse only the parameters. ResponseHeadersFilter, ExceptionMapperBase and XSLTWriterBase use it. Every rel is now quoted, so the readers follow: the TimeMap marker in server.xsl and client.xsl is rel="timemap", and the http tests grep the quoted forms. valueOf still reads an unquoted rel, which an older peer behind the proxy may send. ResponseHeadersFilterTest's negative assertions moved to the quoted form too - left unquoted, "does not contain rel=timemap" would have passed whatever the header said. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tory link no longer leads to a 404 Every document of a versioned dataspace advertises rel=timemap, but the TimeMap answered 404 "has no version history" until a write had made a commit for it. Commits only follow writes, so every document that predated versioning being enabled - imported data, a dataspace switched on later - showed a History link whose dialog said "The version history could not be loaded". GraphVersioningService returns the TimeMap without Mementos instead, and the History dialog says the document has no versions yet and that its next change will be the first. In link-format it lists the Original Resource, which the Mementos named until now and the request names when there are none, the TimeMap itself without a from/until range, and the TimeGate. The TimeGate still answers 404: with no Memento there is nothing to redirect to. TimeMapWriter builds its links with the Link builder rather than by concatenation, and serializes them as RFC 6690 link-values, which allow no whitespace - unlike the header form Jersey writes. GET-timemap-empty.sh puts a document's graph straight into the store, so no write reaches the platform and no commit is made, and asserts the empty TimeMap end to end. The UI spec serves that TimeMap to the History dialog, since every write the suite can make is a commit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…howed as the fragment of their WebID. The bootstrap preloads the signed-in agent's own WebID document, so ac:object-label found that one label and no other. Agents live in the admin dataspace, out of reach of the end-user endpoint the label lookups query, so the dialog now dereferences the authors' documents through the ?uri= proxy before rendering, and tunnels them to ac:object-label as object-metadata. all-settled: an author whose document cannot be loaded keeps the URI fragment, and the history still opens. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…URI, with "(me)" after it. The option is now Web-Client's xhtml:Option over the agent's description in $foaf:Agent, the WebID document the page has already loaded, so it reads as the agent's name; xsl:on-empty keeps the bare URI for an agent the document does not describe. The facet header's fallback to the predicate's local name takes the same instruction in place of an xsl:choose that tested for the very description it then returned. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ive from ORCID_ISSUER A client registered on production ORCID was unknown to the sandbox at authorization, and its ID tokens failed verification against the sandbox JWKS. ORCID_ISSUER (default https://orcid.org) reaches the platform as the orcid:issuer context parameter; the authorize, token, userinfo and JWKS endpoints are built from it, and only tokens from that issuer are accepted. To make room in the ROOT.xml transform, which sits at xsltproc's 32-parameter limit, MAX_CONN_PER_ROUTE, MAX_TOTAL_CONN and MAX_REQUEST_RETRIES become system properties like the other HTTP client settings, still falling back to the ldhc: context parameters. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Temporary. The spec failed on c4cf624 with the /ns property-label query sent twice under refusal against once unrefused; the log shows each send and refusal of that shape in both loads, with a short id per exact request, so the run says whether the second send is a duplicate request or the retry of the first. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…402) The browser moves its current drag target onto a freshly mounted overlay only at the next drag tick. A file dragged in and back out of the window before then fires dragleave on the element underneath, so the overlay-scoped rule never ran and the overlay stayed over the page; an external drag has no dragend to clear it either. The dragleave rule now matches every element and unmounts the overlay whenever relatedTarget is outside it. The file drop spec drives a real external drag through Chromium's Input.dispatchDragEvent, leaving the window both before and after the overlay takes over. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tch cannot pass (#403) A write to a document is a read-modify-write over separate calls to the store: the graph is read, If-Match is checked against that copy, the change is applied in memory and validated, and the whole graph is written back. Nothing spanned those calls, so two writers quoting the same entity tag that both read before either wrote both passed the check, and the second write silently undid the first - the very lost update the precondition exists to refuse. GraphLocks holds a striped set of reentrant locks keyed by graph URI; writeLocked() wraps the window in POST, PUT, PATCH, DELETE and multipart POST. The writer behind reads the graph as the first one left it, quotes a tag that no longer matches and is answered 412. Reentrant because a PATCH that empties a graph completes as a DELETE of it. A unit test races eight writers quoting one tag against a slow in-memory store and expects one 204, seven 412 and a single write; without the lock all eight are accepted. An HTTP test does the same against the root document. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…inds no resources SPARQL.js gives an aliased projection, (?s AS ?resource), as a map rather than the string "?s", and reading only the string left the view's focus variable empty and its whole render failing. ldh:first-var-name reads both shapes. An alias is bound only in the projection, so the rewrites that project something else or append patterns to the WHERE (the result count, the container lookup, the parallax step) first wrap the query as a subquery (ldh:wrap-subquery). Without it the container lookup joined on an unbound variable, matched every triple in the store and exhausted Fuseki's memory. The count's projection and the parallax step's WHERE now match the outer query only, not a subquery's. A first variable that binds values, (YEAR(NOW()) AS ?year), gives rows the DESCRIBE finds nothing for. The count tells the two apart, and the block says the query lists no resources rather than that nothing matched. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… their positional (#404) * Drop the CLI's --base option: document commands never needed it, dataspace commands take the base URI as their positional Every command that addresses a document derived nothing from -b; the scripts it mirrors required the option and never read it either. add file, import csv, import rdf and push now resolve the upload URI against the target document's root, so they print the same URL without being told the base. The commands that act on the dataspace itself - packages, admin clear ontology, admin create ontology/group/authorization, admin import ontology, admin make-public - take its base URI as the positional argument, where every other command puts its target, with LDH_BASE as its default. The HTTP and UI suites move with it; the one test still calling the deprecated create-item.sh uses ldh create item. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Restore the executable bit on the test scripts the rewrite had dropped The scripts were rewritten through a temporary file, which came back as 0644; the suite runs each test with bash, so only GET-file-304.sh, which executes ./create-file.sh directly, noticed: "Permission denied". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The next release removes the CLI's --base option and quotes every Link relation type,
both breaking for clients, so it is a minor release rather than 6.0.2. The platform, the
RDF library and the CLI move together, as cli/pom.xml resolves the library by
${project.version}.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Unreleased section named three of the eighteen commits. It now opens with the migration notes - the CLI's --base option gone, Link relation types quoted, runtime settings kept as a change set - and lists the CLI upload URIs, the Link builder and the native image builds under Changed, and the lost update under concurrent writes, runtime settings overriding the configuration, Restore failing 412 from a historical view, the empty TimeMap, the author names in the History and request access dialogs, the malformed Accept-Language, aliased first variables in views, the file drop overlay and the CI library build under Fixed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.