Roadmap to 10/10
Goal: raise both scores to a defensible 10/10 — portfolio readiness and Linked Art 1.0 adherence. Current honest baseline: ~9 / ~8.5.
Each milestone is one focused PR with explicit acceptance criteria. Check items off as they land.
---
Track A — Portfolio readiness → 10
A1. Reliable, badged CI ✅ done (2026-06-24)
Was: the close-out guard (wired into `pnpm test`/`lint`/`build`) turned CI red whenever the local close-out log was >24h old (e.g. PR #16).
- [x] `scripts/session-closeout.ts` now skips the `--check` guard when `CI` is set (GitHub Actions) — CI tests code, not the local session ritual; the guard still enforces locally. Verified both ways (CI=true → skip; local → enforce).
- [x] README header carries CI, License: MIT, Linked Art 1.0, and tests badges.
- Done when: consecutive green CI runs on `main` (this merge produces the first); badges render. ✅ mechanism fixed; green runs accrue from here.
A2. Dependency & supply-chain hygiene ✅ done (2026-06-24)
- [x] Resolved the 3 moderate `pnpm audit --prod` advisories via `pnpm.overrides`: postcss → `>=8.5.10` (XSS), and the OTel tree consolidated on `@opentelemetry/core`/`resources`/`sdk-trace-base` `^2.8.0` (memory-DoS fix; also corrects `@vercel/otel`'s mis-resolved 1.30.1 peers). Verified: audit clean, tests 1,114, build green.
- [x] `.github/dependabot.yml` covers npm + github-actions + all four pip services (weekly, grouped minor/patch); `ci.yml` gains a `pnpm audit --prod --audit-level high` gate.
- Done: `pnpm audit --prod` reports "No known vulnerabilities found"; Dependabot config active. (One pre-existing upstream `@vercel/otel` peer warning on `instrumentation@0.57.2` remains — not a vulnerability; Dependabot will surface the `@vercel/otel` bump that fixes it.)
A3. Measured test coverage ✅ done (2026-06-24)
- [x] `pnpm test:coverage` runs the suite under c8 with a `--check-coverage` gate (lines 85 / functions 85 / branches 70). CI's test step now runs it, so coverage is measured and gated on every run.
- [x] README shows a coverage badge; current 89.4% lines / 92.1% funcs / 75.5% branch (`src/services` 91.9%, `src/adapters` 91.3%, `src/gateway` 100% — core services well above the 80% bar).
- [x] Also fixed a CRLF-fragility in the B3 conformance-matrix drift test/generator (normalize line endings) so coverage runs clean on Windows.
- Done: coverage runs + gates in CI; badge published; core services ≥ 80%.
A4. Published quality scores ✅ done (2026-06-24)
- [x] `docs/quality.md`(quality.md) publishes the CI-measured numbers: Lighthouse a11y 100/100 (`/`, `/explore`, `/artwork`), axe 0 severe WCAG 2A/2AA violations across 18 routes, and the k6 performance budget met (cached read 73.5 ms < 200, cold read 56.1 ms < 500, facet search 55.1 ms < 300, 0% errors). README gains an a11y badge.
- Done: a11y ≥ 95 (it's 100), the stated p95 performance budget is met, all scores published + CI-gated.
A5. Coherent docs (no remaining walls) ✅ done (2026-06-24)
- [x] Trimmed `docs/roadmap.md` 1,510 → ~420 lines: kept the current Status, SaaS track, Linked Art uplift, Stack decisions, cross-cutting standards, and forward plan; archived the slice-by-slice Era A/B/C saga (~1,100 lines) to `docs/progress/era-history.md`(progress/era-history.md) with a concise pointer. `getStructuredRoadmap` aggregates both so `/api/roadmap` still exposes full phases/milestones to agents.
- Done: the roadmap reads as current; full suite 1,128 green.
A6. (Optional wow) 🟡 script ready — recording pending
- [x] Shot-by-shot demo script + screenshot-gallery plan at `docs/demo-script.md`(demo-script.md) (60–90s, 6 shots).
- [ ] Record + embed the video — needs a human screen-record (can't be automated here).
---
Track B — Linked Art 1.0 adherence → 10
B1. Rights as `Right` entities for ALL providers ✅ done (2026-06-24)
Was: only the Getty adapter emitted full `Right` entities; others flattened rights to labels.
- [x] `src/utils/linked-art-rights.ts` synthesizes a `subject_to` `Right` classified by a CC0 / rightsstatements.org URI, wired into both boundaries — `normalizeIncomingRecord` (import) and `migrateToCurrentSchema` (read, so existing stored records conform too). Getty's `Right` entities are preserved; non-object entities are never given one; default is the honest "Copyright Undetermined".
- Done: every object record carries `Right` + classification; covered by `tests/utils/linked-art-rights.test.ts` (full suite 1,114 green).
B2. SHACL conformance in CI ✅ done (2026-06-24)
- [x] `services/validation-service/shacl_gate.py` validates every provider's pass fixture against the Linked Art SHACL shapes with pyld + pyshacl + rdflib (the same pipeline as the validation service); the JSON-LD expands to CIDOC-CRM and the `crm:E22` targetClass applies (not vacuous — a missing `identified_by`/`label` fails).
- [x] `.github/workflows/shacl-conformance.yml` runs it as a path-filtered CI job (shapes/fixtures/service changes); `pnpm shacl:gate` runs it locally.
- Done: all 14 pass fixtures conform; a regression that breaks CRM expansion blocks the build. (Shapes are still minimal — richer SHACL coverage is follow-on work.)
B3. Systematic per-provider fixture matrix ✅ done (2026-06-24)
- [x] All 13 production providers (+ generic `linked-art`) have pass and fail fixtures in `provider-fixture-manifest.json`, asserted in CI by `validation-architecture-depth.test.ts` (pass conforms, fail rejected) — this part pre-existed.
- [x] `scripts/generate-conformance-matrix.ts` now generates the per-provider table in `conformance-matrix.md` from those fixtures + the capability registry, validating each fixture live with `inspectLinkedArtRecord`. `pnpm conformance:matrix` rewrites it; `conformance:matrix:check` + `conformance-matrix-generated.test.ts` gate drift in CI.
- Done: 13/13 providers pass both directions; the published matrix is generated, not hand-maintained. Full suite 1,116 green.
B4. Faceted / relevance search ✅ done (2026-06-24)
- [x] `src/services/search.ts` ranks matches by hit quality (exact label > prefix > substring > name) and computes `type`/`provider` facet counts over the full match set; `/api/search` exposes `q`/`type`/`provider`/`limit`/`offset` and returns relevance order + facets in the `ld+json` `OrderedCollectionPage`. Tested (`tests/services/search.test.ts`, plus API-level facet/score/filter assertions).
- [x] Conformance-matrix "basic, not faceted" gap closed; Solr 9 documented as the env-gated scale-out backend, this in-app impl as the portable default.
- Done: facets + ranking live + tested; matrix gap closed.
B5. Activity Streams change-feed conformance ✅ done (2026-06-24)
- [x] Aligned `/api/activity` to Activity Streams 2.0: added the AS2 `@context`, AS2 `next`/`prev` page links (kept `nextPage`/`prevPage` aliases), a fuller `partOf` `OrderedCollection` with `first`/`last`/`totalItems`, and the `application/activity+json` media type. `Create`/`Update`/`Delete` items unchanged.
- Done: the feed validates against the AS2 spec shape (`tests/api/activity-as2.test.ts`); suite 1,129.
B6. HTTP SHOULDs ✅ done (2026-06-24)
- [x] Canonical Linked Art entity/collection routes (`objects`, `artworks`, `works`, `agents`, `sets`, `concepts`, `entities`, `records`, `search`) export `HEAD` via a `bodilessResponse(await GET(...))` helper — same headers as GET, no body, mirrors 200/404; `OPTIONS` advertises `GET,HEAD,OPTIONS`. Covered by `tests/api/head-methods.test.ts`.
- [x] HTTP/2 confirmed on the live deploy (`HTTP/2.0 200` via Vercel edge).
- Done: `HEAD` returns headers without a body; HTTP/2 verified live. Full suite 1,128.
---
Recommended sequence
- A1 — green, badged CI (fast, unblocks a clean portfolio surface).
- A2 — vulns + Dependabot (quick, removes a real ding).
- B1 — rights as `Right` entities (the biggest Linked Art win).
- A3 + B3 — measurable rigor (coverage + the fixture matrix).
- B2 + B4 — the heavier conformance lifts (SHACL CI, faceted search).
- A4 / A5 / A6 + B5 / B6 — polish to close out both 10s.
Each step ships as its own PR with the acceptance criteria above met and the full suite green.