unaltraweb 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +18 -11
  3. data/README.md +4 -4
  4. data/_plugins/retained_documents.rb +62 -0
  5. data/docs/_documentation/en/02-tools.md +3 -3
  6. data/docs/_documentation/en/32-development.md +1 -1
  7. data/docs/_documentation/en/40-distribution.md +157 -12
  8. data/docs/_documentation/en/42-docker-image.md +7 -7
  9. data/docs/_documentation/en/45-retained-documents.md +138 -0
  10. data/docs/agents/mcp-contract.md +64 -2
  11. data/docs/agents/owner-closeout-76.md +205 -0
  12. data/docs/agents/owner-followup-76.md +144 -0
  13. data/docs/agents/owner-preparation-2026-09-29.md +254 -0
  14. data/docs/agents/retained-letter-import.md +231 -0
  15. data/docs/agents/visual-companions-0.4.0.md +5 -0
  16. data/lib/unaltraweb.rb +1 -0
  17. data/requirements.txt +2 -0
  18. data/scripts/manual/Dockerfile +7 -4
  19. data/scripts/manual/build_pdf.py +28 -0
  20. data/scripts/manual/templates/manual.tex +1 -0
  21. data/scripts/test_gem_build.py +28 -1
  22. data/scripts/test_wheel_install.py +51 -0
  23. data/scripts/unaltraweb-mcp-bootstrap.sh +33 -6
  24. data/scripts/validate_distribution.py +21 -2
  25. data/src/unaltraweb_mcp/__init__.py +4 -0
  26. data/src/unaltraweb_mcp/artifact-handoff-v1.schema.json +102 -0
  27. data/src/unaltraweb_mcp/artifact_handoff_v1.py +435 -0
  28. data/src/unaltraweb_mcp/artifact_imports.py +368 -0
  29. data/src/unaltraweb_mcp/bundler_runtime.py +214 -0
  30. data/src/unaltraweb_mcp/component-contract.json +20 -20
  31. data/src/unaltraweb_mcp/distribution.py +887 -0
  32. data/src/unaltraweb_mcp/letter_bundle.py +223 -0
  33. data/src/unaltraweb_mcp/pdf_probe.py +63 -0
  34. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9b1d06c849d3893c28fa69a879e93f56acef7a742aa8e2d8ae7df78fa53d4a2
4
- data.tar.gz: '0995fe545e4466b531edc89ed8c8a37ca707e847cc31a8a3acd3647d6b77ecdd'
3
+ metadata.gz: 33193d7900939e3cf2e4e9769e8fd9443e0a7242eaa73aef1d93b8ffcee6e79b
4
+ data.tar.gz: 3ef63e4f55c4b369e0926be413eb2da4d3702f49ac733d84dedc952bb1ec563c
5
5
  SHA512:
6
- metadata.gz: 06dd87a7428129eb5ab81655c892abddf159d223aefec27cbdf5e7b5512a72fe7940061313cec5ccee5032ac1b0343cc6b8390617106c59b76d979b109d73cfc
7
- data.tar.gz: e2a1cc1fe578e4df0968d1f9b9fbc1abbb0cfed254d38c192e7ec24a55e254adf14c9ed57128255f5a18cbaacf68b4fc64a8c519c99d5f87e1a98798db42a1ca
6
+ metadata.gz: eb799646f841a4444d315aa4a71d161ec83acacbef75f36fe00b8db7242699be40147c2829bedee18f249f3085b51328cd18a902f317196d518b4f2b8e11a9f2
7
+ data.tar.gz: cfe5a103146718d7bbae56c9821b2dabdc0fdf1bcde966779ee41ea96c468bd795446202844a56a0974919ce4bca33e2d90e5c6de98e8e95936b1335c44dca86
data/Makefile CHANGED
@@ -1,9 +1,9 @@
1
1
  PYTHON ?= python3
2
2
  override PROJECT := $${MCP_CONSUMER_WORKSPACE:?MCP_CONSUMER_WORKSPACE is required}
3
3
  override PROJECT_ROOT := $(PROJECT)
4
- MCP_RUNTIME_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.5.0
5
- MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.5.0
6
- MCP_RELEASE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:389bc585cdb4fc89d3372f4896a55fe26e15df38b46bc114ce44fdb3f1c8deb9
4
+ MCP_RUNTIME_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.6.0
5
+ MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.6.0
6
+ MCP_RELEASE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:908b4ce54c7bdf355e14ed55b31ed4b9baae319e211af90004a680d1d1cb8692
7
7
  MCP_DOCKER_BUILD_NETWORK ?= default
8
8
  INIT_SITE_PROFILE ?= unaltreselfie
9
9
  NEW_WEB_PROFILE ?= unaltreselfie
@@ -40,10 +40,13 @@ WEB_CAPTURE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-web-capture@sha256:0bf1b
40
40
  WEB_CAPTURE_DEV_IMAGE ?= unaltraweb-web-capture:dev
41
41
  WEB_CAPTURE_DOCKER_BUILD_NETWORK ?= default
42
42
  VEGAVISUALS_CLI ?=
43
- DOCKER_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.5.0
44
- MANUAL_PDF_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:9e0b3a45753c170b795e9a9d6df61580085c113436beac5bf6c8de69b6562097
43
+ DOCKER_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.6.0
44
+ MANUAL_PDF_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed
45
45
  MANUAL_PDF_DEV_IMAGE ?= unaltraweb-manual-pdf:dev
46
46
  MCP_SMOKE_MANUAL_PDF_IMAGE ?= $(MANUAL_PDF_IMAGE)
47
+ MCP_SMOKE_PROJECT ?=
48
+ override MCP_SMOKE_PROJECT := $(value MCP_SMOKE_PROJECT)
49
+ export MCP_SMOKE_PROJECT
47
50
  MANUAL_PDF_LANG ?=
48
51
  MANUAL_PDF_PUBLISH_DRY_RUN ?= 1
49
52
  MANUAL_PDF_CONFIRM_PUBLISH ?= 0
@@ -142,14 +145,18 @@ mcp-smoke: mcp-image manual-pdf-image-dev ## Build and prove a real MCP stdio co
142
145
 
143
146
  mcp-smoke-prebuilt: ## Prove a real MCP stdio connection using the selected prebuilt MCP image
144
147
  docker run --rm --user "$(LOCAL_UID):$(LOCAL_GID)" -e HOME=/tmp --entrypoint python3 "$(MCP_IMAGE)" /opt/unaltraweb/test/mcp_smoke.py
145
- @mkdir -p "$(CURDIR)/tmp/mcp-preview-smoke"
146
- @docker_socket="$${UNALTRAWEB_DOCKER_SOCKET:-/var/run/docker.sock}"; socket_group=$$(stat -c '%g' "$$docker_socket"); \
148
+ @mkdir -p "$(CURDIR)/tmp"
149
+ @project="$${MCP_SMOKE_PROJECT:-}"; \
150
+ if test -n "$$project"; then mkdir -- "$$project" || exit $$?; \
151
+ else project=$$(mktemp -d "$(CURDIR)/tmp/mcp-preview-smoke.XXXXXX") || exit $$?; fi; \
152
+ project=$$(realpath -e -- "$$project") || exit $$?; \
153
+ docker_socket="$${UNALTRAWEB_DOCKER_SOCKET:-/var/run/docker.sock}"; socket_group=$$(stat -c '%g' "$$docker_socket"); \
147
154
  image_id=$$(docker image inspect --format '{{.Id}}' "$(MCP_IMAGE)"); \
148
155
  socket_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$$docker_socket" /var/run/docker.sock); \
149
- project_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$(CURDIR)/tmp/mcp-preview-smoke" /workspace); \
150
- mirror_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$(CURDIR)/tmp/mcp-preview-smoke" "$(CURDIR)/tmp/mcp-preview-smoke"); \
156
+ project_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$$project" /workspace); \
157
+ mirror_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$$project" "$$project"); \
151
158
  docker run --rm --user "$(LOCAL_UID):$(LOCAL_GID)" --group-add "$$socket_group" \
152
- -e HOME=/tmp -e "UNALTRAWEB_DOCKER_ROOT=$(CURDIR)/tmp/mcp-preview-smoke" \
159
+ -e HOME=/tmp -e "UNALTRAWEB_DOCKER_ROOT=$$project" \
153
160
  -e "UNALTRAWEB_PROJECT_USER=$(LOCAL_UID):$(LOCAL_GID)" -e "UNALTRAWEB_MCP_IMAGE=$$image_id" \
154
161
  -e "MANUAL_PDF_IMAGE=$(MCP_SMOKE_MANUAL_PDF_IMAGE)" \
155
162
  --mount "$$socket_mount" \
@@ -368,7 +375,7 @@ manual-pdf-image: ## Ensure the selected versioned Pandoc/XeLaTeX image is prese
368
375
  @docker image inspect "$(MANUAL_PDF_IMAGE)" >/dev/null 2>&1 || docker pull "$(MANUAL_PDF_IMAGE)"
369
376
 
370
377
  manual-pdf-image-dev: ## Build the explicitly named maintainer PDF development image
371
- docker build -f scripts/manual/Dockerfile -t "$(MANUAL_PDF_DEV_IMAGE)" scripts/manual
378
+ docker build -f scripts/manual/Dockerfile -t "$(MANUAL_PDF_DEV_IMAGE)" .
372
379
 
373
380
  define run_manual_pdf_worker
374
381
  @set -e; set --; cidfile=""; \
data/README.md CHANGED
@@ -34,7 +34,7 @@ The default distribution is Docker-first. Generated sites run their normal build
34
34
 
35
35
  ## Current Status
36
36
 
37
- - Public release `v0.4.0` provides the Docker images, Ruby gem and Python wheel as one receipt-bound distribution.
37
+ - Public release [`v0.5.0`](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.5.0) provides the Docker images, Ruby gem and Python wheel as one receipt-bound distribution.
38
38
  - `ghcr.io/dosquartsdedocs/unaltraweb-mcp` is the canonical normal local runtime for generated sites; `ghcr.io/dosquartsdedocs/unaltraweb` is its lower-level Jekyll runtime base.
39
39
  - The Ruby gem supports native Bundler/Jekyll consumers. The modular MCP wheel supports native creation and inspection, and does not bundle the gem, factory checkout, worker images or companion renderers.
40
40
  - PDF, browser-capture and computation environments remain separate images so the normal site image does not carry every heavy toolchain.
@@ -74,11 +74,11 @@ Create a child site directly with the public Docker image:
74
74
  mkdir my-site && \
75
75
  docker run --rm --network none --user "$(id -u):$(id -g)" -e HOME=/tmp \
76
76
  --mount "type=bind,src=${PWD}/my-site,dst=/workspace" \
77
- ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:389bc585cdb4fc89d3372f4896a55fe26e15df38b46bc114ce44fdb3f1c8deb9 \
77
+ ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:36d17edbade77edb40a687f6a744203c6329acb33fbc2eb255e88d9ff1a42c98 \
78
78
  --project /workspace new-web --site-profile unaltreselfie --title "My site" --default-lang en
79
79
  ```
80
80
 
81
- The chained `mkdir` requires a new destination, the digest binds creation to the reviewed `v0.4.0` receipt, and `--network none` keeps scaffold generation offline.
81
+ The chained `mkdir` requires a new destination, the digest binds creation to the reviewed `v0.5.0` receipt, and `--network none` keeps scaffold generation offline.
82
82
 
83
83
  If Python package tooling is already available, the PyPI adapter exposes the equivalent native command:
84
84
 
@@ -129,7 +129,7 @@ make docs-serve DOCKER_IMAGE=unaltraweb:dev
129
129
  make docs-build DOCKER_IMAGE=unaltraweb:dev
130
130
  ```
131
131
 
132
- The public distribution contract selects `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.4.0` for normal generated-site commands. `MCP_RELEASE_IMAGE` pins the reviewed MCP digest from the same `v0.4.0` receipt for gContExt (formerly ContExt), the GNOME Shell extension. The mutable `:main` channel is reserved for explicit maintainer testing; locally built core images use the `:dev` name.
132
+ The public distribution contract selects `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.5.0` for normal generated-site commands. `MCP_RELEASE_IMAGE` pins the reviewed MCP digest from the same `v0.5.0` receipt for gContExt (formerly ContExt), the GNOME Shell extension. The mutable `:main` channel is reserved for explicit maintainer testing; locally built core images use the `:dev` name.
133
133
 
134
134
  The lower-level `unaltraweb` image supplies Ruby, Jekyll and runtime dependencies. The MCP image layers the full reviewed factory and installed Python package on top; generated Make targets load the theme as a path gem from `/opt/unaltraweb`. Native Bundler consumers can instead resolve the independently published gem, and native Python users can install the wheel.
135
135
 
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi"
4
+ require "json"
5
+ require "open3"
6
+ require "timeout"
7
+
8
+ module UnaltrawebRetainedDocuments
9
+ def self.verify(site, output = nil)
10
+ return { "imports" => [] } unless File.exist?(File.join(site.source, ".unaltraweb", "artifacts"))
11
+
12
+ source = File.expand_path("../src", __dir__)
13
+ command = ["python3", "-m", "unaltraweb_mcp.artifact_imports", "--project", File.expand_path(site.source)]
14
+ command += ["--output-folder", output] if output
15
+ stdout, stderr, status = Timeout.timeout(120) { Open3.capture3({ "PYTHONPATH" => source }, *command) }
16
+ result = JSON.parse(stdout)
17
+ raise Jekyll::Errors::FatalException, "Retained document check failed: #{result['error'] || stderr}" unless status.success? && result["ok"] == true
18
+
19
+ result
20
+ end
21
+
22
+ class Generator < Jekyll::Generator
23
+ safe true
24
+ priority :highest
25
+
26
+ def generate(site)
27
+ site.config["unaltraweb_retained_documents"] = UnaltrawebRetainedDocuments.verify(site)["imports"].to_h { |item| [item["id"], item] }
28
+ end
29
+ end
30
+
31
+ class DocumentTag < Liquid::Tag
32
+ def initialize(name, markup, tokens)
33
+ super
34
+ @id = markup.strip
35
+ raise ArgumentError, "retained_document requires one import ID" unless @id.match?(/\A[a-z][a-z0-9-]{0,63}\z/)
36
+ end
37
+
38
+ def render(context)
39
+ site = context.registers[:site]
40
+ item = (site.config["unaltraweb_retained_documents"] || {})[@id]
41
+ raise Jekyll::Errors::FatalException, "Unverified retained document #{@id}" unless item
42
+
43
+ path = site.config["baseurl"].to_s.sub(%r{/\z}, "") + "/" + item.fetch("pdf")
44
+ url = CGI.escapeHTML(path)
45
+ page = context["page"]
46
+ title = CGI.escapeHTML(((page && page["title"]) || @id).to_s)
47
+ %(<figure class="retained-document"><object data-retained-document="#{@id}" data="#{url}" type="application/pdf" aria-label="#{title}" style="width:100%;height:70vh"><a href="#{url}">#{title}</a></object><figcaption><a href="#{url}">#{title} (PDF)</a></figcaption></figure>)
48
+ end
49
+ end
50
+ end
51
+
52
+ Liquid::Template.register_tag("retained_document", UnaltrawebRetainedDocuments::DocumentTag)
53
+
54
+ Jekyll::Hooks.register :site, :post_write do |site|
55
+ source = File.expand_path(site.source)
56
+ destination = File.expand_path(site.dest)
57
+ if destination.start_with?(source + "/")
58
+ UnaltrawebRetainedDocuments.verify(site, destination.delete_prefix(source + "/"))
59
+ elsif !(site.config["unaltraweb_retained_documents"] || {}).empty?
60
+ raise Jekyll::Errors::FatalException, "Retained documents require a project-confined site destination"
61
+ end
62
+ end
@@ -30,10 +30,10 @@ nav_title: Local Tools
30
30
  The current public core runtime image is:
31
31
 
32
32
  ```bash
33
- ghcr.io/dosquartsdedocs/unaltraweb:0.4.0
33
+ ghcr.io/dosquartsdedocs/unaltraweb:0.5.0
34
34
  ```
35
35
 
36
- That image provides Ruby, Bundler, Jekyll system dependencies, ImageMagick, Node for ExecJS and Python tooling needed by local commands. Package-generated `v0.4.0` sites select the matching public MCP image for normal local commands. The external integration fixture can advance from its older release pin independently.
36
+ That image provides Ruby, Bundler, Jekyll system dependencies, ImageMagick, Node for ExecJS and Python tooling needed by local commands. Package-generated `v0.5.0` sites select the matching public MCP image for normal local commands. The external integration fixture can advance from its older release pin independently.
37
37
 
38
38
  ## Generated Site Commands
39
39
 
@@ -143,4 +143,4 @@ When the core docs and all template profiles are running together, use this conv
143
143
  - Keep deploy workflows as thin `workflow_dispatch` wrappers pinned to a reviewed full commit SHA of `dosquartsdedocs/unaltraweb/.github/workflows/site-deploy.yml`.
144
144
  - The optional integration template may retain its local `gh-pages` publishing target for testing that separate workflow.
145
145
  - After the first Docker publish, make `ghcr.io/dosquartsdedocs/unaltraweb` public.
146
- - Confirm `docker pull ghcr.io/dosquartsdedocs/unaltraweb:0.4.0` works without `docker login`.
146
+ - Confirm `docker pull ghcr.io/dosquartsdedocs/unaltraweb:0.5.0` works without `docker login`.
@@ -65,7 +65,7 @@ docker compose -f docker-compose.yml down --remove-orphans
65
65
 
66
66
  This can be resource-heavy because the inherited demo build minifies JavaScript and can generate many responsive WebP images.
67
67
 
68
- The currently public base Dockerfile image is `ghcr.io/dosquartsdedocs/unaltraweb:0.4.0`. Published generated consumers select the higher-level `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.4.0`, which adds the reviewed core and Python control plane. Their Make targets use `/opt/unaltraweb` as a path gem; the RubyGems package remains the optional native Bundler channel. gContExt prepares the full post-release `MCP_RELEASE_IMAGE` digest with `mcp-build`, while `mcp-image`, `mcp-check` and `mcp-smoke` reserve local `:dev` names for source testing. Mutable `:main` channels remain explicit maintainer paths.
68
+ The currently public base Dockerfile image is `ghcr.io/dosquartsdedocs/unaltraweb:0.5.0`. Published generated consumers select the higher-level `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.5.0`, which adds the reviewed core and Python control plane. Their Make targets use `/opt/unaltraweb` as a path gem; the RubyGems package remains the optional native Bundler channel. gContExt prepares the full post-release `MCP_RELEASE_IMAGE` digest with `mcp-build`, while `mcp-image`, `mcp-check` and `mcp-smoke` reserve local `:dev` names for source testing. Mutable `:main` channels remain explicit maintainer paths.
69
69
 
70
70
  The root core build excludes `docs/`. The reference site is published from the `docs/` folder through a dedicated workflow so its root-relative permalinks do not collide with the inherited core demo build.
71
71
 
@@ -25,12 +25,52 @@ The template is the better place to validate gem consumption, centralized styles
25
25
 
26
26
  ## Component Contract
27
27
 
28
- ### 0.5.0 release preparation
29
-
30
- The next coordinated core release is **0.5.0**. It groups the integrated editorial
28
+ ### Pending 0.6.0 retained-letter increment
29
+
30
+ The source branch prepares a separate 0.6.0 identity for native
31
+ [retained-letter import]({{ '/retained-documents/' | relative_url }}).
32
+ Gem, wheel, base runtime and MCP are authorized as `ready` for final same-source
33
+ candidates. The consumer core selects reviewed integration
34
+ `5cf9817489c8dc47cee726bfe42fe3071cd32b85`; the PDF 0.6.0 worker is already
35
+ published, signed and tested at immutable digest
36
+ `sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed`.
37
+ The PDF worker changes to include complete retained documents and the same
38
+ integrity checkers used by its controller. Computation, capture and visual
39
+ companions retain their tested 0.4.0 selections.
40
+
41
+ The checkout's active launcher remains pinned to the published 0.5.1 MCP digest.
42
+ Its receipt and package bytes remain unchanged. Local development images and an
43
+ installed wheel exercise the new import without claiming a public 0.6.0 release
44
+ or changing real consumer sites. The
45
+ [owner acceptance record](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/retained-letter-import.md)
46
+ records the authenticated Carta packet, receiver mapping and relocation proof.
47
+
48
+ ### Published 0.5.1 release
49
+
50
+ [**0.5.1**](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.5.1)
51
+ delivers the installed Docker launcher and runtime-specific generated Bundler
52
+ state. Source `aab5a7b030cd711b40770a3f44ad3a356eab90da` produced the signed
53
+ images and verified gem/wheel. Receipt/tag commit
54
+ `e842c733c8a274279dd5efdc3618e20669f29037` changes only the receipt from that
55
+ first parent. Strict release/publication gates passed before promotion, and
56
+ anonymous registry downloads match the receipt. The checkout launcher now selects
57
+ `ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:908b4ce54c7bdf355e14ed55b31ed4b9baae319e211af90004a680d1d1cb8692`.
58
+
59
+ The four-profile populated-cache roundtrip also passed against the actual signed
60
+ candidate. The selected PDF stays at its published 0.5.0 digest, and computation,
61
+ capture and visual companions retain 0.4.0. See the
62
+ [delivery report](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/owner-closeout-76.md)
63
+ and [issue 76](https://github.com/dosquartsdedocs/unaltraweb/issues/76).
64
+ Strict release validation applies to the receipt/tag revision; subsequent
65
+ post-release launcher changes are ordinary source revisions, not new receipts.
66
+
67
+ ### Previous 0.5.0 release
68
+
69
+ The previous coordinated core release is [**0.5.0**](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.5.0). It groups the integrated editorial
31
70
  review, guided scaffold updates, caption-credit/image behavior and published
32
- Diavisuals/Vegavisuals 0.4.0 acceptance. Package, core/MCP and manual PDF candidates
33
- are verified through the existing source-bound workflows before publication.
71
+ Diavisuals/Vegavisuals 0.4.0 acceptance. Source-bound image/package workflows,
72
+ tag promotion and both Trusted Publishing jobs passed. Anonymous package downloads
73
+ match the receipt and clean native installations were checked.
34
74
  Unchanged already-published computation and web-capture workers retain their own
35
75
  0.4.0 versions and digests. New/pending worker candidates must still match the
36
76
  coordinated release; an old mutable alias cannot qualify for reuse. The selected
@@ -41,19 +81,35 @@ at source `d857f8c9f5fea90cf450c0b30b4e77a37b541275` and is selected by digest
41
81
  `sha256:9e0b3a45753c170b795e9a9d6df61580085c113436beac5bf6c8de69b6562097` in
42
82
  both the factory and the consumer tuple. It is already published and tested, so
43
83
  final candidate receipts cover the remaining ready package/core components.
44
- The factory launcher remains on its previous published image until the normal
45
- post-release pin update. Follow [issue 69](https://github.com/dosquartsdedocs/unaltraweb/issues/69)
46
- for the candidate, receipt, tag and package evidence.
84
+ The 0.5.0 post-release factory launcher selected the MCP digest recorded in receipt
85
+ `3fa855378dcc61dc7b84b8b03812698042e02fed`:
86
+ `sha256:36d17edbade77edb40a687f6a744203c6329acb33fbc2eb255e88d9ff1a42c98`.
87
+ See [issue 69](https://github.com/dosquartsdedocs/unaltraweb/issues/69) for the
88
+ candidate, receipt, tag and package evidence.
47
89
 
48
90
  `src/unaltraweb_mcp/component-contract.json` is the canonical versioned bill of materials. Its `consumer_integration` object is the sole source for the reviewed core Git revision, reusable deploy workflow, manual PDF image digest, and Vega renderer revision. Scaffold templates render that tuple atomically into consumer `Gemfile`, `Gemfile.lock`, and deploy workflow files. `component-contract.schema.json` defines schema version 1. Runtime loading and `scripts/validate_distribution.py` validate the complete document against that schema, then enforce semantic parity between versions, release tags, repositories, references, wheel contents, CLI availability, and consumer integration pins.
49
91
 
50
- The BOM is an interoperability contract, not a bundle. The wheel contains only its Python control/inspection modules, schema/BOM, and clean package-owned scaffolds. In particular it does not contain Ruby theme assets, Docker image layers, factory Make/scripts/docs, TeX, Chromium, computation environments, `diavisuals`, or `vegavisuals`.
92
+ The BOM is an interoperability contract, not a bundle. The wheel contains its Python control/inspection modules, schema/BOM, clean package-owned scaffolds and a small host Docker launcher, described below. It does not include Ruby theme assets, Docker image layers, the factory's build/worker implementations, TeX, Chromium, computation environments, `diavisuals`, or `vegavisuals`.
51
93
 
52
- The selected public core release is `0.4.0`; `v0.3.0` remains the immutable previous distribution. The next-release source BOM reuses immutable compute and web-capture worker digests and selects published `diavisuals v0.4.0` and `vegavisuals v0.4.0` through SHA-256-pinned wheel URLs. Companion references can describe either a provider/release-matching Git reference or a provider/release/version-matching wheel with its content hash. The wheel boundary remains external. The scaffold's Vega revision is the published `68c0b231402ae9485cc34ce530dc5239cb0ec194` commit. These source changes require a new coordinated core release; they do not alter the already published `0.4.0` artifacts or the factory's `MCP_RELEASE_IMAGE` digest. `distribution-check` validates structural integrity for normal CI. `distribution-release-check` blocks coordinated publication while any component is `pending` or `unavailable`; reviewed source authorized to produce the final same-commit candidates is `ready`, while an already-published component is `released`.
94
+ The selected public core release is `0.5.1`; earlier distributions remain immutable. Its BOM reuses immutable PDF, compute and web-capture worker digests and selects published `diavisuals v0.4.0` and `vegavisuals v0.4.0` through SHA-256-pinned wheel URLs. Companion references can describe either a provider/release-matching Git reference or a provider/release/version-matching wheel with its content hash. The wheel boundary remains external. The scaffold's Vega revision is the published `68c0b231402ae9485cc34ce530dc5239cb0ec194` commit. `distribution-check` validates structural integrity for normal CI. `distribution-release-check` blocks coordinated publication while any component is `pending` or `unavailable`; reviewed source authorized to produce final same-commit candidates is `ready`, while an already-published component is `released`. Final receipt values remain immutable after publication.
53
95
 
54
96
  ## Docker-First Hybrid Policy
55
97
 
56
- GHCR is the canonical delivery channel for normal local use. The released package scaffold selects `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.4.0`; existing `v0.3.0` sites can remain on their immutable previous release until deliberately updated. Its `make build`, `make serve` and `make test` targets mount the thin child site and run inside that image. The image contains both the installed Python control plane and the reviewed factory source at `/opt/unaltraweb`, so those targets load the theme as a path gem without downloading PyPI or RubyGems packages.
98
+ ### 0.5.1 component selection
99
+
100
+ The coordinated core identity is **0.5.1**: gem, wheel, base runtime and MCP
101
+ images were published together. The installed host launcher and runtime-aware
102
+ generated Bundler state are included. The unchanged PDF worker retains its
103
+ published 0.5.0 digest, alongside the 0.4.0 computation/capture workers and visual
104
+ companions. A released PDF can be reused only by full digest; new/pending workers
105
+ still require the coordinated version. The historical 0.5.0 receipt remains
106
+ unchanged. Signed image/package evidence is recorded in the 0.5.1 receipt;
107
+ promotion and anonymous-download checks passed before the post-release launcher
108
+ pin was advanced.
109
+
110
+ ### Local delivery
111
+
112
+ GHCR is the canonical delivery channel for normal local use. The released package scaffold selects `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.5.1`; existing sites can remain on their immutable previous release until deliberately updated. Its `make build`, `make serve` and `make test` targets mount the thin child site and run inside that image. The image contains both the installed Python control plane and the reviewed factory source at `/opt/unaltraweb`, so those targets load the theme as a path gem without downloading PyPI or RubyGems packages.
57
113
 
58
114
  Factory registration uses a stricter pin. gContExt runs `mcp-build`, which inspects or pulls the full `MCP_RELEASE_IMAGE` digest, and `mcp-stdio` launches that exact image. Checkout builds use local `:dev` names by default through `mcp-image`, `mcp-check` and `mcp-smoke`, so they do not shadow public semver references unless a maintainer explicitly overrides them. The digest is advanced in a separate post-release change after each new receipt exists; candidate source continues to select the last completed release instead of attempting to embed an unknown self-digest.
59
115
 
@@ -67,6 +123,95 @@ The distribution keeps native channels for interoperability rather than making t
67
123
 
68
124
  These remain real package boundaries: the MCP image installs the Python package and uses the core through Ruby's gem interface. The policy only makes their public registry installation optional for Docker users. It does not combine all toolchains into one image or duplicate worker layers in the wheel or gem.
69
125
 
126
+ ### Installed Docker launcher
127
+
128
+ 0.5.1 ships **`unaltraweb-mcp-docker`** and a complete host launcher
129
+ under the installation prefix's `share/unaltraweb-launcher/`. The published 0.5.0
130
+ wheel predates this addition; its receipt and bytes remain unchanged. An installed
131
+ wheel containing the launcher can use the already-published full GHCR runtime
132
+ without a local core checkout:
133
+
134
+ ```bash
135
+ unaltraweb-mcp-docker prepare
136
+ unaltraweb-mcp-docker check
137
+ unaltraweb-mcp-docker smoke
138
+ unaltraweb-mcp-docker serve --project /absolute/consumer
139
+ ```
140
+
141
+ The installed default selects its package's full MCP release image, currently
142
+ `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.5.1`. It resolves that selection to the
143
+ local immutable image ID before executing. The checkout's `MCP_RELEASE_IMAGE`
144
+ is a separate digest pin advanced only after publication; it is not the installed
145
+ wheel's default. This avoids sending a new package back to an older MCP while
146
+ also avoiding an impossible self-digest in the candidate image/wheel.
147
+ `--image` selects a different explicitly prepared image for a test or a reviewed
148
+ adoption. `prepare` only inspects/pulls; `check` and `smoke` use the local image ID,
149
+ without pulling, building, mounting a consumer or starting a preview. `serve`
150
+ requires an explicit consumer or inherited `MCP_CONSUMER_WORKSPACE`; it starts one
151
+ labelled stdio container and preserves the canonical host-path mirror for workers.
152
+ `down --project /absolute/consumer` uses the same project-scoped cleanup helper.
153
+
154
+ `unaltraweb-mcp-docker path` locates the installed profile from wheel metadata;
155
+ `manifest` prints its discovery descriptor. The profile ships the same native
156
+ schema-v1 `mcp-factory.yml`, a small launcher-only Makefile, and the bootstrap,
157
+ project-ID, Docker CSV mount and cleanup scripts. Its `${factoryRoot}` is this
158
+ installed directory, and the declared `make -C` transport and lifecycle targets
159
+ remain usable. That directory can also be relocated as a unit and run with Make,
160
+ a POSIX shell, Linux core utilities and Docker, without host Python or Ruby.
161
+ The console adapter itself requires the wheel's Python interpreter. Linux/amd64
162
+ is the acceptance platform; other host/platform combinations remain unverified.
163
+
164
+ This adapter launches the **full container runtime**. The native `unaltraweb-mcp`
165
+ CLI keeps the exact wheel-only/factory-required boundary declared in the BOM.
166
+ Installing the adapter does not install Jekyll, workers or companion servers on
167
+ the host, register a client, update a consumer scaffold, or change an active MCP.
168
+
169
+ ### Separate selections and compatibility evidence
170
+
171
+ The site Makefile's `MCP_IMAGE`, native Gem/core revision, PDF worker, global MCP
172
+ registration and companion selections are separate parts of an effective tuple.
173
+ TIG/TIGIT retain build defaults 0.4.0; Geodisseny retains 0.5.0. A global MCP
174
+ selection does not rewrite those defaults. Tests use synthetic sites,
175
+ image-specific test resources and dynamically allocated loopback preview ports.
176
+
177
+ Compatibility evidence is a set of tested tuples, not a continuous version range.
178
+ The [initial owner preparation report](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/owner-preparation-2026-09-29.md)
179
+ records all four 0.5.0 profiles, manual PDF coverage, the 0.4.0 comparison and
180
+ the reproduced retained-cache failure. The 0.5.1 correction is recorded in the
181
+ [follow-up report](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/owner-followup-76.md).
182
+ Range adoption belongs at
183
+ the native dependency/version checks, companion receipt checks and atomic
184
+ consumer-integration selection. Exact wheel hashes, image digests and published
185
+ receipts remain identity evidence even if future compatibility rules accept a
186
+ range. Central catalogue/range fields await the accepted hub integration.
187
+
188
+ ### Generated Bundler state
189
+
190
+ 0.5.1 keys generated dependencies by the effective Ruby/platform, Bundler,
191
+ installed gem inventory, core inputs and Bundler configuration, rather than a
192
+ mutable Docker tag. The offline resolver prepares a verified cache under
193
+ `tmp/unaltraweb-bundle/<identity>/`. Returning to an identity reuses its cache;
194
+ changing identities does not rewrite another runtime's lock. Credential-bearing
195
+ Bundler environment/configuration values contribute only hashes to the receipt.
196
+
197
+ New native build/preview targets execute with invocation-owned copies of that
198
+ generated state. Bundler can complete local default-gem checksum metadata without
199
+ rewriting the verified cache or disabling checksum validation. An
200
+ explicit `LOCAL_GEMFILE` is author-managed: its existing lock is required and
201
+ used frozen. Project `Gemfile`, `Gemfile.lock` and Bundler configuration are
202
+ preserved. Edited or incomplete generated caches fail for inspection instead of
203
+ being silently repaired. Failed preparation directories remain under `tmp/`.
204
+
205
+ For unchanged historical package Makefiles, the updated MCP prepares the same
206
+ runtime-specific cache and passes invocation-owned Gemfile/lock copies to the
207
+ old recipes. The retained `tmp/Gemfile.local.lock` remains untouched, so a later
208
+ 0.4.0 build can use its original selection. This adapter requires the Makefile to
209
+ match its recorded scaffold baseline; authored Makefile customizations retain
210
+ their own dependency policy. Those consumers can deliberately adopt the updated
211
+ native targets through the normal reviewed scaffold workflow. New native targets
212
+ require a containing core/runtime; the already-published 0.4.0 and 0.5.0 images do
213
+ not acquire the correction automatically.
214
+
70
215
  ## Optional Wheel And Doctor
71
216
 
72
217
  A clean `unaltraweb-mcp` wheel works without a factory checkout for `version`, `new-web`, top-level `doctor`, constrained source management, scaffold synchronization, `site-doctor`, HTML audit, and pure inspection where feasible. Examples include `mcp list-tools`, `starter-templates`, `detect-site`, `site-context`, `profile-check`, content/language/bibliography inventories, and `build-health`.
@@ -139,7 +284,7 @@ For that reason:
139
284
 
140
285
  ## Docker Runtime
141
286
 
142
- Release `0.4.0` publishes the selected base runtime, MCP runtime and specialized workers. Local maintainers continue to use explicit development names such as `unaltraweb:dev`; generated sites select the reviewed semver MCP image rather than `main` or `latest`.
287
+ Release `0.5.1` publishes the selected base/MCP runtime and packages while pinning the verified PDF worker and reusing unchanged specialized workers. Local maintainers continue to use explicit development names such as `unaltraweb:dev`; generated sites select the reviewed semver MCP image rather than `main` or `latest`.
143
288
 
144
289
  The base runtime owns Ruby, Jekyll and system dependencies. The MCP image builds on its exact candidate digest and adds the full reviewed factory plus the Python package. Specialized workers remain separate. This keeps each layer focused without adding Chromium, TeX or computation stacks to every site; the coordinated core-image workflow still rebuilds and verifies runtime, MCP and manual PDF candidates together.
145
290
 
@@ -13,21 +13,21 @@ weight: 140
13
13
  permalink: "/docker-image/"
14
14
  nav_title: Docker Images
15
15
  ---
16
- Release `v0.4.0` currently publishes two core images. Published generated sites select the self-contained MCP/site image for normal local commands:
16
+ Release `v0.5.0` currently publishes two core images. Published generated sites select the self-contained MCP/site image for normal local commands:
17
17
 
18
18
  ```text
19
- ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.4.0
19
+ ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.5.0
20
20
  ```
21
21
 
22
22
  It contains the Python control plane and the reviewed factory at `/opt/unaltraweb`. Its lower-level base is:
23
23
 
24
24
  ```text
25
- ghcr.io/dosquartsdedocs/unaltraweb:0.4.0
25
+ ghcr.io/dosquartsdedocs/unaltraweb:0.5.0
26
26
  ```
27
27
 
28
28
  The base provides Ruby, Bundler, Jekyll system dependencies, ImageMagick, Node for ExecJS and Python tooling. Generated Make targets run in the MCP image and load layouts, styles and plugins as a path gem from `/opt/unaltraweb`. RubyGems remains an optional native Bundler channel rather than a download required by the local Docker path.
29
29
 
30
- The `v0.4.0` receipt binds matching `unaltraweb:0.4.0` and `unaltraweb-mcp:0.4.0` references to their tested immutable digests. The semver aliases were promoted only after the coordinated receipt and tag checks completed.
30
+ The `v0.5.0` receipt binds matching `unaltraweb:0.5.0` and `unaltraweb-mcp:0.5.0` references to their tested immutable digests. The semver aliases were promoted only after the coordinated receipt and tag checks completed.
31
31
 
32
32
  gContExt prepares and launches the MCP image through the full digest in `MCP_RELEASE_IMAGE`. That post-release pin is separate from the semver scaffold reference and cannot be shadowed by checkout builds, which use local `:dev` names. A new release advances the pin only after its receipt records the published digest.
33
33
 
@@ -58,7 +58,7 @@ make mcp-image
58
58
  make mcp-smoke-prebuilt MCP_IMAGE=unaltraweb-mcp:dev
59
59
  ```
60
60
 
61
- Both core GHCR packages are public, and unauthenticated `v0.4.0` pulls have been verified.
61
+ Both core GHCR packages are public; their `v0.5.0` references resolve to the verified receipt digests.
62
62
 
63
63
  ## Computation Images
64
64
 
@@ -188,8 +188,8 @@ Selector-based screenshot authoring uses a separate Playwright image rather than
188
188
  ghcr.io/dosquartsdedocs/unaltraweb-web-capture@sha256:0bf1bc67fe63e1440bffe708a168beefa11c54441650a871ab99380d362f7c1e
189
189
  ```
190
190
 
191
- The `v0.4.0` contract reuses this already-published worker by immutable digest. The image contains pinned Playwright/Chromium, the capture worker, the Python status controller, and the core visual sources used in fingerprints. `make web-capture-image` builds the explicitly named `unaltraweb-web-capture:dev` maintainer image; set `WEB_CAPTURE_IMAGE` to that name when testing it. The manual `Web capture image` workflow publishes default-branch, commit, and semver/release tags to GHCR.
191
+ The `v0.5.0` contract reuses the already-published 0.4.0 worker by immutable digest. The image contains pinned Playwright/Chromium, the capture worker, the Python status controller, and the core visual sources used in fingerprints. `make web-capture-image` builds the explicitly named `unaltraweb-web-capture:dev` maintainer image; set `WEB_CAPTURE_IMAGE` to that name when testing it. The manual `Web capture image` workflow publishes default-branch, commit, and semver/release tags to GHCR.
192
192
 
193
- Published `v0.4.0` sites consume `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf:0.4.0`. `manual-pdf-image` reuses or pulls the selected image instead of rebuilding it locally. Maintainers use `make manual-pdf-image-dev` and then pass `MANUAL_PDF_IMAGE=unaltraweb-manual-pdf:dev` for local PDF runtime changes.
193
+ Published `v0.5.0` scaffolds consume `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:9e0b3a45753c170b795e9a9d6df61580085c113436beac5bf6c8de69b6562097`. `manual-pdf-image` reuses or pulls the selected image instead of rebuilding it locally. Maintainers use `make manual-pdf-image-dev` and then pass `MANUAL_PDF_IMAGE=unaltraweb-manual-pdf:dev` for local PDF runtime changes.
194
194
 
195
195
  Rendering creates an ephemeral Docker `--internal` network shared only by Jekyll and Chromium, keeps browser requests on the preview origin, blocks service workers, popups, and WebSockets, drops Linux capabilities, uses a read-only container root and bounded resources, and writes only the declared PNG/SVG outputs under the mounted project. Ordinary checks run without browser execution or network access.
@@ -0,0 +1,138 @@
1
+ ---
2
+ title: Import A Retained Letter
3
+ description: Verify and retain a Carta letter bundle, display its PDF on the web and include it in a manual.
4
+ lang: en
5
+ ref: retained_documents
6
+ profiles:
7
+ - unaltredocs
8
+ documentation_profiles:
9
+ - local-authors
10
+ - core-developers
11
+ section: Build A Site
12
+ weight: 240
13
+ permalink: /retained-documents/
14
+ nav_title: Retained Documents
15
+ ---
16
+
17
+ A retained letter combines its original PDF with the source, rendering inputs and
18
+ provenance needed to inspect its origin. The importer keeps that complete unit in
19
+ the receiving repository and creates a native page or chapter referencing the PDF.
20
+ The website displays the original; a manual PDF includes all its pages.
21
+
22
+ This capability belongs to the **0.6.0 development increment**. It requires a
23
+ containing Python package and Jekyll core, plus the matching PDF worker for manual
24
+ output. The published 0.5.1 runtime predates it. Changing the global MCP selection
25
+ does not update a site's Gemfile, Makefile or PDF-worker selection.
26
+
27
+ Native gem builds need Python with `PyYAML>=6,<7`, `pypdf>=6,<7` and
28
+ `markdown-it-py>=3,<5`. The containing MCP/PDF images provide these dependencies;
29
+ the containing reusable deployment workflow installs the PDF/text parsers when
30
+ retained imports are present.
31
+
32
+ ## Supported Input
33
+
34
+ The receiving profile accepts leaf `letter-pdf-v1` bundles from **Carta
35
+ 0.3.0rc1**, using the existing artifact handoff v1 envelope. Verification covers
36
+ the supplied sender SHA-256, complete file inventory, retained render recipe,
37
+ templates, source references, drawable resources and renderer identity. PDF
38
+ inspection is bounded and rejects encrypted files, embedded or external files,
39
+ JavaScript and unsupported actions. Internal destinations and textual HTTP,
40
+ HTTPS and email links are supported.
41
+
42
+ Renderable metadata is checked independently of the retained Pandoc AST. A
43
+ resealed bundle with an unretained local link in a subject or author field is
44
+ rejected even when its older parsing evidence does not mention that link.
45
+
46
+ Limits are 64 MiB for the payload unit, 32 MiB for the PDF and 1–64 pages. The
47
+ supported source subset excludes body images, raw markup, TeX, math and citations;
48
+ attachments remain text labels. Composite bundles, edited PDF variants and
49
+ Diapora composition require separate receiving profiles.
50
+
51
+ Obtain the bundle's expected SHA-256 through the sender's trusted handoff. A hash
52
+ computed only from an unknown local manifest establishes consistency, not its
53
+ origin. Importing never executes the retained recipe or contacts the producer.
54
+
55
+ ## Import Into A Consumer
56
+
57
+ Start with an initialized consumer Git repository. Place the complete incoming
58
+ bundle under a workspace-relative directory such as `tmp/incoming/letter/`.
59
+ The recovery area under `tmp/` must be ignored and untracked; durable destinations
60
+ must be eligible for version control.
61
+
62
+ Review a plan using the installed CLI. Here `BUNDLE_SHA` is the sender's verified
63
+ manifest digest:
64
+
65
+ ```bash
66
+ unaltraweb-mcp --project /absolute/consumer mcp import-artifact-bundle \
67
+ --path tmp/incoming/letter/bundle.json --sha256 "$BUNDLE_SHA" \
68
+ --import-id correspondence --content-path _chapters/en/correspondence.md \
69
+ --title "Retained correspondence"
70
+ ```
71
+
72
+ To apply the reviewed request, repeat it with `--apply --confirm-import`.
73
+ The MCP equivalent is `import_artifact_bundle` with `dry_run=false` and
74
+ `confirm_import=true`; its default is a read-only plan.
75
+
76
+ Choose a new Markdown destination under `_pages/`, or `_chapters/` for a manual,
77
+ or `_documentation/` for a documentation site. An executable source owning the
78
+ same Markdown basename blocks creation. The generated document starts as a draft
79
+ in the consumer's default language, with a literal local permalink.
80
+
81
+ The resulting paths are:
82
+
83
+ | Path | Purpose |
84
+ | --- | --- |
85
+ | `.unaltraweb/artifacts/correspondence/bundle/` | Complete, unchanged incoming seal, outside the web output |
86
+ | `.unaltraweb/artifacts/correspondence/integration.json` | Standard v1 integration record and byte-preserving PDF mapping |
87
+ | `.unaltraweb/artifacts/correspondence/binding.json` | Native content path and integration-record digest |
88
+ | `assets/documents/correspondence.pdf` | Public PDF, identical to the retained original |
89
+ | `_chapters/en/correspondence.md` | Native chapter with the retained-document component |
90
+
91
+ Version the complete durable unit together. The incoming directory and ignored
92
+ recovery journal are not runtime dependencies. The retained archive is excluded
93
+ from website output, but remains ordinary repository content.
94
+
95
+ ## Edit And Render The Native Document
96
+
97
+ Add explanatory prose to the generated page or chapter while preserving its
98
+ literal permalink and component:
99
+
100
+ {% raw %}
101
+ ```liquid
102
+ {% retained_document correspondence %}
103
+ ```
104
+ {% endraw %}
105
+
106
+ On the web, the component renders a PDF object with a labelled download link.
107
+ The build checks the bound page's exact local PDF URL and the emitted PDF bytes.
108
+ Exposing the retained archive in the website is an error. In a manual, the PDF
109
+ builder includes every original page and fingerprints the entire retained unit
110
+ and its checker implementation. A controller/worker mismatch therefore fails
111
+ freshness verification rather than silently accepting an older checker.
112
+
113
+ Run `artifact_import_check` or the CLI equivalent before building:
114
+
115
+ ```bash
116
+ unaltraweb-mcp --project /absolute/consumer mcp artifact-import-check
117
+ unaltraweb-mcp --project /absolute/consumer mcp artifact-import-check --output-folder _site
118
+ ```
119
+
120
+ `site_check` and `site_doctor` include the native integrity check. For a local
121
+ manual review, use `manual_pdf_preview_prepare`, then `build_site` and
122
+ `preview_start`. Review the web page and composed PDF, then clean only the
123
+ receipt-owned preview copies through `manual_pdf_preview_clean`.
124
+
125
+ ## Preservation And Recovery
126
+
127
+ An identical reimport preserves authored prose. A changed mapped PDF, conflicting
128
+ destination, unsafe path or modified seal blocks the operation; existing files
129
+ are never overwritten. After an interrupted import, unchanged partial files may
130
+ be adopted by an explicit retry of the same request. Differing partial files
131
+ require inspection. The operation retains its prepared tree and journal under
132
+ `tmp/unaltraweb-artifact-imports/` and performs no destructive rollback.
133
+
134
+ The native check verifies references and content after the incoming producer copy
135
+ has been removed or the receiving repository has moved. It also detects missing
136
+ content, incomplete retention and altered mappings. The generic v1 verifier can
137
+ independently inspect `integration.json`; it does not replace the native source
138
+ and rendered-output checks.