This plan implements DSH.01 in dependency order. Each work package requires executable evidence before it is complete. Later work must not weaken an accepted error, limit, or compatibility rule to make its fixtures pass.
| Package | Status | Requires | Deliverable | Acceptance |
|---|---|---|---|---|
| DSH-P01 | complete | Existing doc-shell/v2 reader | Additive collection.json, DocShell.Generate.Collection and collection descriptor | DSH-V01/V02 plus collection integrity requirements below; no network or process startup |
| DSH-P02 | complete | DSH-P01 | DocShell.Generate.Cohort, canonical payload digest, normalized source provenance | DSH-V03; digest excludes time, random IDs, and absolute workspace paths |
| DSH-P03 | complete | DSH-P01/P02 | Site, Page, navigation/link types and SiteSource validation | DSH-V04–V06; all public structs/functions documented and typed |
| DSH-P04 | complete | DSH-P03 | Heading/anchor, reading-order, locale/audience/version, canonical/source/edit and redirect projection | DSH-V04–V06 with property tests for route and anchor normalization |
| DSH-P05 | complete | DSH-P03/P04 | Section-aware search records, built-in deterministic JSON adapter and adapter behaviour | DSH-V07; fixed query corpus and browser-neutral output |
| DSH-P06 | complete | DSH-P03–P05 | Renderer behaviour, normalized capability/requirement/context/asset contracts, reserved feature IDs and shared fallback/enhanced/connected conformance fixtures | DSH-V09/V10; fixtures published with the package for independent renderers |
| DSH-P07 | complete | DSH-P02–P06 | Atomic static exporter, site manifest, sitemap, robots and llms outputs | DSH-V08; clean build, rollback, subpath and output-bound evidence |
| DSH-P08 | in progress | DSH-P06/P07 | Hosted/static semantic parity and live-capability degradation tool | Core comparison is complete; DSH-V11 still requires two independent renderer implementations |
| DSH-P09 | complete | DSH-P01–P08 | Documentation, Livebooks, benchmarks, compatibility and packaged-consumer qualification | DSH-V12 and the core release evidence recorded below |
| DSH-P10 | planned | DSH-P03/P06 | Preserve the hosted graph/source-cohort boundary and validate a host publication/OpenAPI pair before renderer invocation | DSH-V13; hosted projection needs no synthetic per-repository collection; cross-surface and mixed-generation pairs fail |
| DSH-P11 | in progress | DSH-P03/P06/P07 | Freeze portable artifact block/profile/receipt schemas and v2 state-specific capability fixtures | Static records and tests implemented; complete schema/limit and compatibility matrix remains open |
| DSH-P12 | in progress | DSH-P11 | Add explicit per-call profile adapters, block validation and requirement/admission projection | Chart/drawing fixtures, runtime selection, callback containment, concurrent isolation and three-seed model checks pass |
| DSH-P13 | in progress | DSH-P12/P07 | Join verified local variants, search/text fallback and atomic export | Selected closure, original-byte checks, prior-tree preservation, emitted-script refusal and root/subpath file export tests pass |
| DSH-P14 | in progress | DSH-P13; actual producer and independent readers | Qualify document previews, renderer/native semantic parity and fresh package consumers | First producer's installed archive/static document join and full package gate pass; native/browser/manual target evidence remains open |
P10 is outside the core site qualification record below. The existing
generation_id joins artifacts written by one DocShell.Build run; it does not
bind independently supplied hosted graph and OpenAPI inputs. The build invokes
the OpenAPI adapter and presentation source separately, then creates that ID
when writing artifacts.
Before implementing validation:
- Define an additive pair contract and its admission point. Preserve existing
doc-shell/v2fields and keep host authorization policy outside DocShell. - Require comparable context on both sides. An opaque binding alone cannot detect a token reused across source views, graph positions, locales, releases, or disclosure surfaces.
- Keep claim authentication in the host. DocShell checks declared equality before renderer invocation.
Public API shape
Foundation hardening before site work
This work qualifies the P01 collection implementation. It repairs the extraction library and does not advance P02–P09 or establish renderer/export conformance.
| Work | Status | Required evidence |
|---|---|---|
| Clarify source/file identities, projection compatibility and canonical JSON | complete | Specification, README, usage rules and notebook guidance agree |
| Check JSON, descriptor and source input boundaries | complete | Canonical JSON fixtures/properties, malformed descriptor/extraction regressions, consistent OpenAPI errors and invalid UTF-8 build tests |
| Validate complete indexed provenance and preserve source extensions | complete | Collection integrity regressions and generated build/load properties cover the real multi-release corpus, reserved/duplicate IDs, malformed/future artifacts and projector failure before publication |
| Secure and bound corpus loading | complete | Root spellings and parent-symlink regressions; exact file/total/count/depth limits; JSON escape properties and duplicate-key rejection; prior compatible corpora |
| Make stale deletion transactional | complete | Transaction tests cover deletion rollback and lock ownership; collection regression verifies unchanged manifest on obstructed deletion |
| Strengthen presentation and cache contracts | complete | Equal-title regression/properties; semantic reference and JSON-extension checks; opt-in member search; concurrent snapshots and configurable reload timeout tests |
| Qualify performance and package consumers | complete | Collection scaling and full benchmark suite; nine locked/unlocked/compatible-minimum consumers; four notebooks; complete mix check; repeated malformed-input and publication review |
Keep the existing public facade when separating descriptor, provenance, digest, and filesystem responsibilities. Commit each coherent behavior with its tests. Mark a row complete only with executable evidence and update docs in that commit.
Qualification record — 2026-09-11
Local verification used Elixir 1.18.4 and OTP 27.3.4.15. The existing CI matrix remains unchanged; other Elixir/OTP pairs were not locally rerun or remotely dispatched as part of this work.
| Check | Result |
|---|---|
Full mix check, without automatic retry-only behavior | 277 tests, 28 properties, 16 doctests; zero failures; 97.4% coverage |
| Compilation, strict Credo, Dialyzer, Doctor, ExDoc, formatting and dependency audits | Pass; 100% documentation/typespec coverage; no ignored Dialyzer warnings added |
| Compile without optional integrations | Pass |
| Executable notebooks | All four pass, 55 executable cells |
| Unpacked Hex archive consumers | Core, Plug and Ash pass for locked, unlocked and selected compatible-minimum dependencies |
| Benchmarks | All suites run; measurements refreshed, including preparation and import at 1,000–16,000 documents |
The minimum consumer set is Jason 1.4.0, EarmarkParser 1.4.8 and YamlElixir 2.11.0, except the Ash consumer needs Jason 1.4.5 for its Decimal 3 dependency. Old EarmarkParser versions emit upstream deprecation warnings on modern Elixir; these are not suppressed. This is selected direct-dependency qualification, not an exhaustive historical/transitive dependency matrix.
On the original synthetic 16,000-document diagnostic fixture, median-of-three preparation time changed from 2,766.9 ms to 48.9 ms and import from 5,454.7 ms to 876.3 ms. These local observations are not timing assertions or asymptotic proofs. The committed collection benchmark records independent elapsed-time and allocated memory measurements. Source loops now use indexed lookup and prepend/reverse; canonical object ordering still requires key sorting.
Follow-up review also closed integer/float projection mismatches, contradictory embedded ASTs, orphan OpenAPI content, protocol-encoder failures, colliding member metadata keys and changed bytes under a reused cache generation ID. Descriptor, filesystem, provenance and canonical JSON responsibilities have separate modules; the compatible collection facade remains.
Import requires a stable caller-owned directory. Checksums establish internal consistency, not source authenticity, and publication is not power-loss atomic. The package provides neither an OS sandbox nor a visual renderer. No workflow, remote ref, release tag, repository visibility or dependency lock was changed. Do not change schemas, dependency ranges, workflow checks, release refs, or repository visibility merely to make a check pass.
Core site qualification record — 2026-09-22
Core site publication was qualified locally on Elixir 1.18.4 and OTP 27.3.4.15. Fresh endpoint builds also passed on Elixir 1.17.3/OTP 27.3.4.15 and Elixir 1.20.4/OTP 28.5. These checks qualify the DocShell package; they do not substitute for the two independent renderer results still required by P08.
| Check | Result |
|---|---|
Full mix check, without retry-only behavior | 303 tests, 28 properties, 16 doctests; zero failures; 95.3% coverage |
| Compilation, strict Credo, Dialyzer, Doctor, ExDoc, formatting and dependency audits | Pass; 100% documentation, moduledoc and typespec coverage |
| Compile without optional integrations | Pass |
| Supported-version endpoints | Full tests pass on Elixir 1.17/OTP 27 and Elixir 1.20/OTP 28 |
| Executable notebooks | All five pass, 62 executable cells |
| Unpacked Hex archive consumers | Core, Plug and Ash pass with locked, newly resolved and selected compatible-minimum dependencies |
| Package contents | Site contracts, conformance fixture, specification, plan, notebooks and benchmark reports are present |
| Site benchmark | Projection and complete staged export measured at 10, 100 and 500 pages, with search/output sizes and allocated memory |
The 500-page local benchmark recorded a 204.50 ms median for projection and a 338.92 ms median for full static replacement. Benchee reported 585.74 MB and 311.04 MB of allocated memory respectively; these are allocation measurements, not peak resident memory or performance assertions.
The minimum consumer set retains the dependency versions recorded in the earlier qualification section.
Old minimum EarmarkParser releases emit upstream deprecation warnings on modern Elixir, and Ash emits optional Igniter warnings when Igniter is absent; neither warning originates in DocShell.
Site modules
The implementation exposes these public modules while keeping projection and filesystem publication mechanisms in private supporting modules:
DocShell.Generate.Collection
DocShell.Generate.Cohort
DocShell.Presentation.Limits
DocShell.Presentation.Site
DocShell.Presentation.Page
DocShell.Presentation.Link
DocShell.Presentation.Heading
DocShell.Presentation.SiteSource
DocShell.Presentation.SiteProjector
DocShell.Presentation.SearchAdapter
DocShell.Presentation.Renderer
DocShell.Presentation.Renderer.Capabilities
DocShell.Presentation.Renderer.Capability
DocShell.Presentation.Renderer.CapabilityRequirement
DocShell.Presentation.Asset
DocShell.Presentation.StaticExporter
DocShell.Presentation.ConformanceExpected failures use tagged tuples and stable reason atoms with structured
context. Host callbacks are invoked behind exception capture and result-shape
validation, following DocShell.Presentation.GraphProjector.
Compatibility sequence
- Add collection and site contracts without changing existing
doc-shell/v2files. - Generate
doc-shell-site/v1only when a caller invokes the site builder. - Publish conformance fixtures before renderer packages claim support.
- Qualify the existing Svelte renderer and one independent HTML renderer.
- Treat any required change to an existing
doc-shell/v2field as a separate schema decision with a migration fixture. doc-shell/v2is such a decision: module navigation items carry member references instead of member records, members carrydoc_state, member metadata defaults to an allow-list, and files are compact canonical JSON.test/fixtures/presentation-v2.jsonis its fixture; v1 files are rejected.
Required quality evidence
Portable artifact delivery
The experimental extension supplies generic document capabilities. P11–P14 are in progress: the static implementation and its tests exist, while the complete compatibility and reader qualification matrix remains open. The new API and schema IDs apply to this implementation; they do not alter v1 meaning or establish independent reader qualification.
The October commit review retained regressions for three implementation defects: runtime-list order changing admission, script-free exports accepting JavaScript MIME parameters/aliases, and empty sites skipping artifact-option validation. All three first failed on their observable behavior and then passed after corrections in the admission/export owners. The focused portable artifact suites pass 18 tests. These results do not close the remaining schema/limit, independent reader, native, or human target qualifications.
P11 fixes original block bytes, descriptor/schema digests, semantic subjects, all variant bytes and expected refusal/admission outcomes. Freeze a technical illustration and an unrelated chart fixture before writing core adapters. Include mixed static/JS/live variants, no-JS policy, duplicate descriptors, unknown optional/essential profiles and altered block/fallback bindings.
P12 extends the existing AST and site projection owners; it adds no global plugin registry, remote discovery, producer dependency or rendering process. Compare admission with an independent small model at three fixed seeds and exercise two differently configured callers concurrently. Every callback fault returns a located error rather than partial publication.
P13 passes prepared local bytes through the existing asset/export owner. A
script-free variant must survive actual offline/JS-disabled presentation;
declaring runtime: [] is not a passing result. Asset source disclosure also
applies to thumbnails, descriptions, search and fallbacks. Corrupt or absent
required assets preserve the previous complete output tree.
P14 supplies a local review page from the exact projected data, including artifact/variant IDs, anchors, selected capability, limitations, fallback and generated SVG/PNG.
The artifact producer supplies reference/candidate/difference images; DocShell does not calculate geometry or approve baselines.
Test / and
subpath exports, print, dark/monochrome/high zoom and reader restart. An HTML
reader and a native artifact consumer record the same semantic observations;
native paint and human assistive tasks require their own target evidence.
Run the full package gate and current CI compatibility matrix when implementing these rows. Ship the new fixture/schema documents in the fresh package archive. The current v1 renderer pair and hosted publication/OpenAPI obligations remain open independently; artifact previews cannot close them.
Existing site quality evidence
- Unit tests cover every structured error and public default.
- StreamData covers route normalization, anchor uniqueness, input ordering, canonical JSON, and output path containment.
- Corpus fixtures include modules, guides, Livebooks, release entries, OpenAPI, unknown source kinds, nested navigation, multiple locales, and versions.
- Hosted graph fixtures prove DocShell consumes one already-authorized projection without repository discovery, cohort inference or renderer-side privacy filtering.
- Hosted public/internal fixtures carry matching narrative/OpenAPI publication, graph-position, locale and release bindings; cross-surface and mixed-generation pairs fail before renderer invocation.
- Static fixtures run from
/and a repository subpath with JavaScript blocked and enabled. - The package archive contains the public schemas, conformance fixtures, and usage documentation.
- Benchmarks record projection and export time, allocated memory, page count, search size, and output bytes for small and large fixed corpora.