lwsd

LWS conformance — status and findings

Target: the current editor’s drafts in w3c/lws-protocol (July 2026, at commit 7832003): lws10-core, lws10-searchindex, lws10-notifications, lws10-authn-ssi-did-key, and lws10-authn-ssi-cid.

Implementation: lws/plugin.js + helpers (notify.js, access.js, cidauth.js, didkey.js, jwt.js) as a JSS plugin (jss ≥ 0.0.219).

Touchstone — conformant

Touchstone master at cd01608 (221 tests, re-baselined on the 19 Oct 2026 core WD and the 15 Oct authn suites), run by scripts/touchstone.sh --auth (Authentication, ReachableFixtures, HarnessIssuedTokens declared; public read off; alice the writer; page size 4), 21 Oct 2026:

210 passed, 0 failed, 0 cantTell, 11 inapplicable — conformant. The inapplicable eleven: three need SamlTrust; three test move choices this storage does not make (move-keeps-identifier-content-and-links wants preservesIdentifier: true, move-container-refused-without-container-support a storage that moves data resources only, move-refused-without-capability one with no capability); five are preconditions for optional behaviour (Content-Location on search results, a paginated-but-single-page listing, a first-page link on a one-page search, Prefer: set-linkset combined updates, container access that does not reach members). Reports: reports/touchstone/2026-10-21-master-cd01608/.

History: 14 Oct 2026, 6a3206e (205 tests, 5 Oct drafts): 197 passed, 0 failed, 8 inapplicable — conformant, confirmed by Erich Bremer’s independent run (https://ebremer.com/lws/conformance). 19 Oct, his run of the re-baselined harness against the then head: 197 passed, 2 failed (linkset-up-not-redirected, move-refused-without-capability — a patch of the up link was ignored with 204 where the new draft requires a refusal or a move), 22 inapplicable. Both fixed by implementing §9.6 (below).

Batteries — npm test runs all seven (145 checks)

Battery Checks Server config Covers
conformance.js 78 LWS_ANON_WRITES=1 LWS_PAGE_SIZE=5 core, pagination, content PATCH, type index/search (+ strict 400/415 errors), the LWS profile in JSON-LD and Turtle, up-link refusals, notifications with RFC 9421 signature verification
move.js 15 LWS_ANON_WRITES=1 §9.6 moving: capability, data-resource and container moves, 200 + Content-Location + 301 on the old identifiers, ETags of both containers, user links kept, refusals (missing / non-container / removed up, cycles, name collisions), one Move activity
auth.js 6 LWS_WRITERS=<did:key> 401 challenge + did:key self-issued JWT accept/reject
cid.js 3 LWS_WRITERS=<sub> LWS_CID_ALLOW_LOOPBACK=1 CID self-issued JWT: dereference sub → controlled identifier doc → verify
grants.js 12 LWS_PUBLIC_READ=0 LWS_WRITERS=<admin> ODRL access-grant engine: read-gating, foaf:Agent public grants, action scoping, dateTime constraints, authz-filtered search
as.js 22 LWS_PUBLIC_READ=0 LWS_WRITERS=<did:key> authorization server: RFC 8414 metadata, JWKS, RFC 8693 token exchange (valid / invalid_target / unsupported_grant_type / expired / wrong audience / corrupted), at+jwt validation at the storage (corrupted, alg none, unknown kid), RFC 9728 resource metadata, owner vs non-owner
oidc.js 9 LWS_PUBLIC_READ=0 LWS_WRITERS=<webid> LWS_CID_ALLOW_LOOPBACK=1 OpenID Connect ID Tokens as subject tokens: discovery via the subject’s CID document, key from the OP’s JWKS, expired / alg none / corrupted / untrusted issuer / missing azp / wrong aud refused
JSS_BIN=$(command -v jss) npm test        # orchestrates all four on scratch ports

Implemented

lws10-core — GET/HEAD (ETag, Content-Type, Link up/type/linkset/lws#storage), Range (RFC 7233), conditional GET (304); container representations as application/lws+json with conneg (lws+json / ld+json / json / ld+json;profile) and Vary: Accept; POST-to-create with Slug and container typing; PUT update-only (428/412/204/404); content PATCH via merge-patch for JSON resources; DELETE (204, 409 non-empty, Depth: infinity); linkset resources (RFC 9264, merge-patch); storage description discovery; RFC 9457 problem+json; link-based pagination; optional 507 quota (LWS_QUOTA_BYTES).

lws10-searchindex — TypeIndexService + TypeSearchService, types/relations derived from Link headers at write time (no body parsing, per the draft); full conjunctive-normal-form filter (GET + POST); structural relations excluded; strict errors (415 wrong media type, 400 malformed body / non-array type / non-absolute-URI value); no-match = empty; authorization filtering — results limited to what the client may read, totalItems over the client-specific view.

lws10-notifications — NotificationService; WebhookSubscription CRUD; AS2 Notification envelopes on every write; recursive container topics; RFC 9421 HTTP Message Signatures (ES256) over @method @scheme @authority @path content-type content-digest, with the signing key published as a CID verificationMethod in the storage description and a content-digest (RFC 9530). The battery cross-verifies the delivered signature against the published key.

Authorization (lws-access-requests.html) — 401 WWW-Authenticate: Bearer as_uri=…, realm=…; AccessRequestService / AccessGrantService endpoints (GET/POST, DELETE); a real ODRL Access Profile engine — nested access[] policies with actions (read/modify/create/delete mapped to HTTP methods), assignee (URI or foaf:Agent for public), target (type class + URI-prefix), and constraints (client / mediaType / type / purpose / dateTime with eq/neq/isAnyOf/isNoneOf/lt/lteq/gt/gteq). Grants drive both read and write auth.

Authn suites — did:key (Ed25519 + P-256) and CID (sub-dereference to a controlled identifier document, kid→verificationMethod, RFC 7515 §5.2) self-issued JWTs, accepted directly as Bearer credentials. none rejected; sub==iss==client_id, exp/iat enforced.

Not implemented: the OpenID and SAML authn suites, and the full OAuth token-exchange authorization flow — all three require an external authorization server / identity provider, outside a storage server’s scope (C11/C12). lws10-vocab publishing (a doc-gen concern).

Draft drift since July (7832003 → 19 Oct 2026 WD)

Tracked against Touchstone, which baselines on the 19 Oct core WD and the 15 Oct authn suites. Absorbed items are ticked; the rest are the upgrade list (JavaScriptSolidServer/JavaScriptSolidServer#621).

Findings — spec observations (S) and host/plugin-API gaps (H)