Skip to content

Develop - #341

Draft
namedgraph wants to merge 6 commits into
masterfrom
develop
Draft

Develop#341
namedgraph wants to merge 6 commits into
masterfrom
develop

Conversation

@namedgraph

Copy link
Copy Markdown
Member

No description provided.

namedgraph and others added 6 commits August 6, 2026 12:09
* Serve raw ontology graphs without RDFS inference

Resolve the application ontology's owl:imports closure natively via
ontapi (OntModelFactory.createModel over a ScopedGraphRepository view)
instead of manually flattening the closure and materializing an
RDFS-inferred model. No inference is applied anymore — every consumer
(constructor/constraint inheritance, client-side (rdfs:subClassOf)*
queries) traverses hierarchies explicitly. rdfs:Class terms are promoted
to owl:Class in a separate union member so no document graph is
polluted; closure union graphs are cached in a bounded map on
Application, keyed by ontology URI.

The shared repository now only ever holds raw per-document graphs, which
ProxyRequestFilter serves directly for closure documents — asserted
triples only, identical to a direct document GET. The DESCRIBE fallback
over the in-memory closure (terms minted in external namespaces) is
inference-free as well. This fixes inferred rdf:type rdfs:Resource
leaking into proxied namespace documents, where the extra type produced
multi-token @typeof and silently degraded View blocks to a generic
property list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix ScopedGraphRepository.contains() dropping resolvable imports

ontapi consults GraphRepository.contains() before get() when resolving
an ontology's imports closure. PrefixGraphRepository.contains() reports
cache state (loaded graphs), not resolvability, so every import that
resolves through a bundled location mapping (dh, sp, spin, foaf, sioc,
sd), SPARQL-first loading or HTTP was answered with false on first
resolution — and ontapi silently substituted an empty ontology graph
for it (its ignoreUnresolvedImports fallback). The closure kept its
shape but lost the content of every such import: SPIN constraints
vanished, so validation enforced nothing (422 tests wrote through,
eventually applying invalid dataspace settings and cascading into
NPEs), and vocabulary term lookups came up empty. This is what failed
the HTTP test suite in CI.

contains() now attempts resolution through the backing repository
(which loads and caches the graph) after the cache checks, reporting
absent only for genuinely unresolvable ids. Adds a production-shaped
regression test: ns# ontology importing the SPARQL-seeded ldh#
vocabulary with its transitive imports resolved through the real
bundled location mappings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Alias only repository-held closure ids under their document URIs

ontapi keys imports under their declared ontology IRIs, which need not
be repository entries: a content-addressed upload is cached under its
uploads/ URI while declaring a foreign ontology IRI. The doc-URI
aliasing loop called repository.get() on such declared IRIs, which fell
through to an HTTP dereference of the foreign IRI (e.g.
https://example.org/test) during ontology load — failing the load and
the ontology-import-upload-no-deadlock HTTP test. Guard the loop with
isCached() so only graphs the shared repository actually holds get
aliased. Adds a mismatched-IRI import case to the closure regression
test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix GET-proxied-ontology-ns.sh assertions for closure DESCRIBE semantics

The admin ontologies/namespace/ document stores the ontology but the
closure keys it under the <ns#> ontology URI, so a proxied GET of the
document URI is answered by the closure DESCRIBE fallback — the
document's own #-fragment term descriptions — not the raw graph branch.
Assert on a class minted in the document's hash namespace (mirroring
the original #related_View regression) instead of the made-up-namespace
classes, which only appear under their own namespace document URI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Remove Linked Data proxy DESCRIBE-over-closure fallback

The proxy is document-keyed transport; term lookups over the ontology
closure belong on /ns (SPARQL), not on a DESCRIBE synthesized from the
proxy target URI. Drop the fallback and its ParameterizedSparqlString/
QueryExecution imports; the isCached closure-cache branch (raw per-doc
graphs, no inference) still serves closure documents.

Realign tests: delete GET-proxied-ontology-ns.sh (it only exercised the
removed DESCRIBE path and dereferenced ontology terms via the admin doc
URI, which was never a supported path). Add GET-ns-no-query.sh (raw /ns
ontology graph, no rdfs:Resource leak) and GET-proxied-mapped-vocab.sh
(dct:title, foaf:Person, skos:Concept served from the static prefix
mapping; skos also covers fragment-strip + xml:base resolution).

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

* Make the Linked Data proxy dumb: drop ontology-closure serving

Remove the getOntology()/isCached branch that answered ?uri= requests from
the app ontology owl:imports closure cache, plus the now-unused ontology
injection, getOntology(), and PrefixGraphRepository/Application/EndUserApplication/
OntModel imports. The proxy is now dumb transport: bundled-vocab file cache
(isMapped) + SSRF-checked external fetch. Ontology terms are served by /ns.

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

* Fix GET-proxied-mapped-vocab SIGPIPE on large vocab responses

The assertions piped the whole vocabulary graph through `echo | grep -q`.
`grep -q` exits on first match and closes the pipe while `echo` is still
writing; with `set -o pipefail` the SIGPIPE'd `echo` (write error: broken
pipe, exit 141) fails the pipeline whenever the response exceeds the ~64 KiB
pipe buffer — so a *successful* match killed the test. Only this test trips
it, being the only one that returns entire vocabulary documents (40-113 KiB).

Read from a here-string instead (temp file, no pipe to break), and match the
full language-tagged label literal the bundled documents actually carry.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
)

The four view controls (order-by dropdown, facet headers, parallax
properties, rdf:type facet values) resolved predicate/class labels by
proxying each term's vocabulary document (GET ?uri=<ac:document-uri(term)>),
then applying ac:label to the response. With the proxy no longer serving
ontology terms, route these through the app's /ns SPARQL endpoint instead.

- view-results chain: add a property-metadata load step (mirroring the
  existing object-metadata step) that DESCRIBEs the result predicates over
  /ns before ldh:render-view, threading $property-metadata through to the
  order-by and facet-header rendering.
- order-by + facet headers: render labels synchronously from
  $property-metadata via ac:label (local-name fallback for terms absent
  from the closure); drop the per-predicate proxy promises and the
  ldh:order-by-response / ldh:facet-filter-response handlers.
- parallax + rdf:type facet values: swap each per-term proxy GET for a
  POST /ns DESCRIBE $Type VALUES { <term> }; the response is still
  application/rdf+xml so the existing handlers are unchanged.

Verified against the unesco-thesaurus demo: on /concepts/concept1002/ the
redundant vocab-document proxy fetches drop (skos/core 9->5, rdf 2->1,
prov 2->1), the SKOS view predicates now resolve via /ns, and the 429/502
the redundant load triggered are gone.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
POST-proxied-external-query.sh proxied a live query to dbpedia.org/sparql,
whose public endpoint intermittently returns 502 in CI. Rename it to
POST-proxied-cross-origin-query.sh and point it at the admin app's SPARQL
endpoint (a different origin than the end-user app), so it still exercises
the ProxyRequestFilter remote-fetch + SPARQL-results re-serialization path
but runs deterministically against a local target. Use the owner cert since
the admin endpoint is ACL-protected, and assert the response is actual
SPARQL results rather than only a 200 status.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Replace /add and /generate endpoints with client-orchestrated graph writes

Move the "Add data" and "Generate containers" orchestration to the client
over the uniform Graph Store Protocol interface, removing the server-side
fetch/SSRF surface (pen-test LNK-002) and collapsing two special-purpose
endpoints into standard per-document writes.

- Add data: the submit handler splits by the presence of a spin:query input.
  The add/clone variant fetches dct:source through the same-origin ?uri=
  proxy as RDF/XML (CORS + Jena format conversion) and POST-appends it to the
  sd:name target (ldh:add-data-source-response / ldh:add-data-form-error). The
  import-ontology variant is unchanged and still RDF/POSTs to /transform.
- Generate containers: builds one container document per checked class and
  PUTs them via parallel ixsl:all fan-out (ldh:generate-containers-fanout ->
  ldh:generate-containers-join), seeded by ixsl:resolve so the requests run in
  an active promise context. The view block is now correctly wrapped as
  ldh:Object -> rdf:value -> ldh:View (the endpoint's bare ldh:View bypassed
  ldh:InvalidContentBlockType validation).
- Delete Add.java, Generate.java and their Dispatcher locators. /transform is
  retained until a client-side SPARQL engine lands.
- http-tests: drop the obsolete /add and /generate tests (the system/ suite is
  unregistered); add add/GET-proxied-source-POST-append.sh and
  add/PUT-generate-container.sh. CHANGELOG updated.

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

* Fix generate-containers dialog: parent init, disabled Generate, async schema load

- Initialise the parent typeahead with the current container (ldh:LoadTypeaheads
  from ldh:base-uri, matching btn-save-as), which was lost when the form stopped
  carrying a source param.
- Disable the Generate button until the schema is loaded; enable it in
  ldh:endpoint-classes-response once the class list is populated.
- Make Load schema fully async: the service-endpoint resolution used a blocking
  document() fetch (the "TO-DO: asynchronous request"). Replaced with an
  ixsl:resolve -> ldh:load-schema-endpoint -> ldh:load-schema-results promise
  chain, so the request no longer blocks and the progress cursor shows.

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

* Add RDF data: seed target graph from the local dataspace, reject remote targets

The "Add RDF data" dialog seeded its target graph typeahead from
ldh:base-uri(.), which resolves to the proxied remote resource when viewing
one (ac:document-uri(ac:uri())). So adding data while viewing a proxied
document defaulted the write target to that remote and proxied the append to
it (403). The source is still ldh:base-uri (the remote being imported).

- btn-save-as now seeds the graph typeahead from ac:absolute-path(ldh:request-uri())
  (the local browser location), which is always a local dataspace document.
- Guard the append: a cross-origin target renders an inline error instead of
  proxying the write. ldh:add-data-form-error now tolerates a missing response
  so pre-fetch validation can reuse it.

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

* Condense Unreleased CHANGELOG entries to one line each

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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