Skip to content

Develop - #397

Merged
namedgraph merged 17 commits into
masterfrom
develop
Sep 29, 2026
Merged

namedgraph merged 17 commits into
masterfrom
develop

Conversation

@namedgraph

Copy link
Copy Markdown
Member

No description provided.

namedgraph and others added 17 commits September 29, 2026 10:33
…ocument they came from

A reference like /uploads/{sha1} carries no authority, so the browser fills in the origin it is
displayed on - the proxying dataspace - and the authored media 404s there. The proxy-mode rewrite in
ldh:XHTMLContent excluded exactly those references while resolving the relative ones beside them, so a
docs page proxied into another dataspace rendered its prose and its links correctly and its images
broken. Only fragments stay unresolved now, because they address the rendering rather than the source.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The docs under atomgraph.github.io/LinkedDataHub/ are a stale static mirror;
the live documentation is the docs.linkeddatahub.com dataspace, whose paths
are identical, so the rewrite is a straight prefix swap. The Maven project
URL points at linkeddatahub.com.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… of the chain: ldh:retry-request re-fired $context('request') whatever response key it was retrying, so a chart whose results POST was rate-limited got the RDF/XML of its query's document back as the results, and drew "Table has no columns" with one row per resource in that document.

The request is looked up under the key paired with the response (chart-results-request for chart-results-response, metadata-request for metadata-response, ...); a step that threads no paired key, as ldh:view-results-thunk reuses 'request', still falls back to it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… instead of looking it up in the ixsl:style() map, which is built by enumerating the computed style: Chromium 131, still Playwright's bundled build, enumerates no custom properties, so every chart colour came back empty and Google Charts failed with "Cannot read properties of null (reading 'color')".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… request is refused with 429 once, and to draw in the design tokens where the browser does not enumerate custom properties: rate-limit.spec checks that the retry re-sends the query POST and the drawing is labelled by kind, tokens.spec hides custom properties from getComputedStyle's enumeration the way Chromium 131 does and checks the series is the --ldh-blue-500 colour.

Against a client SEF without b87fc9b and 0ffe1a4 each fails on its own defect ("Table has no columns", "Cannot read properties of null (reading 'color')"), as owner and anonymous; with them the chart specs pass 30/30 over three repeats.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sserts it still answers: every server-side HTML render calls back into the platform through the proxy for its /sparql and /ns labels, each callback needs a request thread of its own and holds a pooled connection while it waits, so once renders outnumber the connector's threads they wait on each other until reads time out. linkeddatahub.com wedged that way on 2026-09-29 under a scanner probing non-existent paths, every 403 and 404 page being a full render. The stack for it shrinks the connector to 16 threads (HTTP_MAX_THREADS, a new entrypoint setting applied by platform/server.xsl after letsencrypt-tomcat.xsl has written server.xml, which sizes only the HTTPS connector) and the client pool to 4 per route, production's ratio at a size a runner can saturate, and pushes the socket timeout to ten minutes so a timeout cannot pass for a recovery. It runs apart from the HTTP suite, since a failed burst leaves the platform wedged for whatever follows. On 6.0.0 it fails; a pool-wait timeout alone shortens the outage to 113 s and it still fails.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…it.spec refuses every block request on the fixture page once and checks that each is sent again as itself, that nothing is fetched more often than on an unrefused load, and that the chart, the view and the object block all render; chart/rate-limit.spec, which asserted it on the chart alone, is folded into it.

The retry is ldh:retry-request's and serves every block's request chain, so the chart was only where the defect showed. Against a client SEF without b87fc9b the spec fails on the chart ("Table has no columns"), and with the chart assertion taken out it still fails on six view and object metadata requests (four /sparql, two /ns) that were never re-sent; with the fix it passes 6/6 over three repeats, as owner and anonymous.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…lient pool is sized to the connector, so a burst of renders can no longer deadlock the platform against itself. Every server-side HTML render calls back into its own dataspace through the proxy for the page's labels, and each callback is answered by one of the same Tomcat's request threads while the render holds another; once renders outnumbered the threads, every thread was a render waiting for a callback no thread was free to serve, and nothing completed until the client's read timeout, which is sized for a stalled backend. ClientUriRewriteFilter, the one place that recognizes such a request and sends it to the proxy, now gives it a connect and read timeout of its own (CLIENT_SELF_REQUEST_TIMEOUT, 5 s), and SendHTTPRequest hands the client's ProcessingException to the stylesheet as the SaxonApiException its xsl:try catches, so a lookup that gave up is a missing label rather than a failed render. The image's pool grows from 20/40 to 200/400 connections, the connector's thread count: a self-call holds a pooled connection while it waits for another thread, so a smaller pool queued them behind each other and a burst drained one bounded wait at a time (218 s to recover on the load stack, against 78 s sized to its 16 threads). The pool-wait gets a code default of 30 s, matching the image's, where it was unbounded outside the image. tests/load starts from settings of its own rather than the repository's, whose package imports are the developer's.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…linkeddatahub.com is no longer shadowed by bundled copies. prefix-mapping.ttl mapped the whole https://packages.linkeddatahub.com/ prefix to the bundled packages.ttl, so every URI on that origin resolved to the catalog - the packages dataspace's own translations.rdf included, and its every HTML page failed with an empty ac:label() in the breadcrumb; the three mappings and the bundled packages.ttl, editor/taxonomy/package.ttl and ns.ttl go, and the registry is read over HTTP. With the mappings gone a descriptor naming its ontology's document (lds:ontology <ns/>) while the ontology inside is <ns/#> loaded two graphs of that name into the closure, and ontapi refused the second: declarePackageImports now imports the ontology IRI the resolved graph declares, and loadOntology assembles the closure without the package ontologies, retracting their imports, when it cannot be assembled with them. OntologyFilterTest covers both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ttps://packages.linkeddatahub.com/, so they depend on neither its reachability nor its current content; the materialization test failed when the published descriptor still named its ontology <ns/> while the test pinned the bundled copy's IRI. tests/http/config declares a packages.localhost:4443 dataspace on the root's datasets, as test.localhost is; tests/packages holds a copy of the taxonomy editor package and publish.sh, which pushes it and declares its stylesheet by the URI of the upload the push made; run.sh publishes it before the datasets are stored, so every reset restores it, and exports PACKAGES_BASE_URL, which the three package tests import from. The UI suite publishes the same registry onto packages.<end-user host> and imports from it unless UI_TESTS_TAXONOMY_PACKAGE names another package. ldh uploads .xsl and .xslt as text/xsl, which Files.probeContentType does not detect: a stylesheet uploaded as application/octet-stream answers the platform's text/xsl request with 406.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…OS package: the fixture's ontology label and the UI README say so, and client.xsl's comment on keeping the server-rendered body no longer names a package at all, since a platform stylesheet has no business knowing one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s. A PUT whose body did not type the document was validated while the document was untyped, then typed dh:Item by the server and written, so an ontology file pushed as a document came out a dh:Item without a title; put() now checks a document it types itself before writing it, with validateConstraints, which runs the SPIN and SHACL checks alone - validate() would announce the model's authorizations a second time. A POST, plain or multipart, validated only its body, where a constraint spanning the document had nothing to apply to; both now check the document as it will be written, the upload before any file is stored, and the upload still needs no If-Match since it is appended rather than written back. The multipart PUT, the document form's, wrote the form's triples as the graph and skipped put(Model) altogether - no type or container, no created/creator/owner, no dct:modified, no If-Match; it now writes the files and hands the model to put(Model). PATCH and the new checks share describeViolations, so a 422 describes only the violating resources.

The PUT tests that created untitled documents title them, PUT-empty.sh becomes PUT-empty-422.sh, and new tests cover the untitled PUT (PUT-missing-title-422-body), the POST whose document becomes invalid (POST-invalid-content-block-422, POST-multipart-invalid-content-block-422) and the multipart PUT (PUT-multipart-metadata, -412, -created, -missing-title-422).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…398)

* Extract the vocabularies and document shapes into linkeddatahub-rdf

The RDF a client has to send to create a container, add a chart or grant an
authorization was described in static buildModel methods hanging off picocli
@command classes, reachable only by depending on the CLI - so Web-Algebra's
ldh-* operations, which build the same documents through REST-VKG's execution
context rather than through Jersey, had no way to share them and would have
had to restate every shape. A shape restated is a shape that drifts. rdf/ now
builds com.atomgraph:linkeddatahub-rdf with Jena as its only dependency: what
is shared is the shape of the request body, not how it is sent, so neither
consumer inherits the other's transport.

The eighteen builders move off the command classes into classes named for what
they build - Documents (container, item), Blocks, Views, Queries, Services,
Imports, Acl and Ontologies - with BaseCommand.createSubject becoming
Subjects.of, since fifteen of them needed it. The nine vocabulary classes and
Slugs, SequenceNumbers, Digests and Updates move across unchanged. Commands are
now argument parsing and a call. URIRewriter splits rather than moving whole:
childURI, encodeSlug and adminBase are conventions the platform itself applies
and belong in the library as URIs, while rewrite is the --proxy option sending a
request somewhere other than where its URI says, which stays a CLI concern with
origin now private.

The platform keeps its own com.atomgraph.linkeddatahub.vocabulary, still
duplicated with the library's. Collapsing them would make the platform depend on
rdf/, and the Dockerfile builds the webapp from COPY src and COPY pom.xml alone,
so the dependency has to point away from the platform rather than at it.

cli/pom.xml resolves the library by ${project.version}; make cli installs it
first, and make cli-version and release.sh's sync_cli_version now version both
poms together, since the two must move as one or the CLI stops resolving.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Publish linkeddatahub-rdf to Maven Central alongside the platform

The library had no distributionManagement and no publishing plugin, so a client
outside this machine could not resolve it at all - REST-VKG's ldh-* operations
would have had only a local install to depend on. rdf/pom.xml now declares the
central-portal-snapshots repository and the central-publishing plugin, the
licenses, developers and scm blocks Central rejects a release without, and a
release profile attaching sources, javadoc and GPG signatures, mirroring what
<releaseProfiles>release</releaseProfiles> activates for the platform.

release.sh deploys it immediately after release:perform, which carries reactor
modules only. It builds from the release tag via git archive rather than from
the working tree, because sync_cli_version has moved rdf/pom.xml on to the next
development version by that point. Inside the irreversible zone on purpose: a
platform release whose pinned library is absent is a release whose clients
cannot build.

Building the release profile also caught a javadoc reference to SP#Describe,
which the trimmed vocabulary does not carry - it holds Construct and Select.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Declare the snapshot repository the CLI resolves its library from

cli/ is its own build, so the platform pom's <repositories> do not reach it, and
it had never needed any of its own: everything it depended on is released to
Maven Central. linkeddatahub-rdf between releases is not - Central serves no
snapshots - so resolution succeeded only where the library happened to be in the
local repository, which is to say on the machine that had just installed it. CI
resolved nothing and failed on the dependency.

Verified against a local repository that never had the install, which is the
state CI starts from: the CLI builds and its 86 tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… landed.

Two of the nine entries were there; the rest are the RDF library's own publication,
the write validation, the package ontology and registry fixes, the 429 retry, the
chart token lookup, the CLI's stylesheet media type and the documentation links. The
two that were there are cut to one line each, as the rest are. Omitted: the Taxonomy
Editor renaming, the load and package test suites, the chart specs and the version bumps.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@namedgraph
namedgraph merged commit a936a27 into master Sep 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant