unaltraweb 0.4.0 → 0.5.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +5 -5
  3. data/README.md +19 -7
  4. data/_plugins/figure_captions.rb +47 -10
  5. data/_sass/_documentation.scss +7 -5
  6. data/_sass/_manual.scss +7 -0
  7. data/docs/_documentation/en/02-tools.md +4 -4
  8. data/docs/_documentation/en/03-usage.md +61 -0
  9. data/docs/_documentation/en/13-unaltremanual.md +1 -1
  10. data/docs/_documentation/en/20-syntax.md +14 -0
  11. data/docs/_documentation/en/25-caption-credits.md +120 -0
  12. data/docs/_documentation/en/26-image-backgrounds.md +103 -0
  13. data/docs/_documentation/en/31-template.md +1 -1
  14. data/docs/_documentation/en/32-development.md +1 -1
  15. data/docs/_documentation/en/40-distribution.md +25 -5
  16. data/docs/_documentation/en/42-docker-image.md +7 -7
  17. data/docs/_documentation/en/43-workspace-path-policies.md +232 -0
  18. data/docs/_documentation/en/44-editorial-review.md +237 -0
  19. data/docs/agents/action-prompts/00-start-site-session.txt +10 -5
  20. data/docs/agents/action-prompts/22-manual-style-audit.txt +3 -1
  21. data/docs/agents/manual-authoring-components.md +38 -0
  22. data/docs/agents/mcp-contract.md +102 -10
  23. data/docs/agents/visual-companions-0.4.0.md +74 -0
  24. data/docs/assets/img/caption-credits-demo.svg +19 -0
  25. data/scripts/editorial_check.py +12 -0
  26. data/scripts/image_background_check.py +12 -0
  27. data/scripts/manual/build_pdf.py +94 -16
  28. data/scripts/manual/filters/figure-captions.lua +65 -10
  29. data/scripts/manual/templates/manual.tex +2 -1
  30. data/scripts/test_gem_build.py +32 -2
  31. data/scripts/test_reproducible_jekyll_build.py +1 -1
  32. data/scripts/test_wheel_install.py +28 -0
  33. data/scripts/unaltraweb-mcp-bootstrap.sh +1 -1
  34. data/scripts/validate_distribution.py +18 -3
  35. data/src/unaltraweb_mcp/component-contract.json +28 -28
  36. data/src/unaltraweb_mcp/editorial.py +495 -0
  37. data/src/unaltraweb_mcp/editorial_sources.py +504 -0
  38. data/src/unaltraweb_mcp/image_backgrounds.py +334 -0
  39. data/src/unaltraweb_mcp/image_probe.py +149 -0
  40. data/src/unaltraweb_mcp/processes.py +146 -0
  41. metadata +15 -2
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: Check Image Backgrounds
3
+ description: Read-only transparency warnings for raster images and self-contained SVG figures.
4
+ lang: en
5
+ ref: image_backgrounds
6
+ profiles: [unaltredocs]
7
+ documentation_profiles: [local-authors, site-designers, contributors, core-developers]
8
+ section: Design And Customize
9
+ weight: 318
10
+ permalink: "/image-backgrounds/"
11
+ nav_title: Image Backgrounds
12
+ ---
13
+
14
+ Publication images should have an opaque background chosen for their content.
15
+ Any opaque colour is valid. A transparent PNG can be just as difficult to read
16
+ as a transparent SVG when enlarged over the website, so the check examines image
17
+ content rather than assuming that one filename extension is safe.
18
+
19
+ `image_background_check` is an **advisory**. It reports transparent and
20
+ unverifiable images, without modifying files, painting them white, changing
21
+ their dimensions or turning a style warning into a publication failure.
22
+
23
+ ## What Is Checked
24
+
25
+ - PNG, including palette and RGB `tRNS` transparency, and supported JPEG, GIF,
26
+ WebP, BMP, TIFF and AVIF images are decoded with Pillow. A PNG with an alpha
27
+ channel whose values are all fully opaque passes the check.
28
+ - Animated raster images are inspected frame by frame within a fixed budget.
29
+ A transparent frame is reported even if the first frame is opaque.
30
+ - Self-contained SVG and SVGZ images are rasterised with CairoSVG into a bounded
31
+ viewport, with no supplied background colour. This samples the asset's own
32
+ background; a CSS background behind the image in the page does not count.
33
+ - SVG embedded PNG/JPEG captures are supported. External resource loading is
34
+ disabled. Dynamic SVG, masks, filters and unsupported resources are reported
35
+ as unverifiable rather than assumed opaque.
36
+
37
+ SVG inspection is a raster sample at a maximum side of 1536 pixels, not proof of
38
+ opacity at every possible scale or under every SVG renderer. Raster inspection
39
+ allows up to 16 megapixels per frame, 32 frames and 64 million frame-pixels in
40
+ total. Files are limited to 32 MiB (8 MiB of SVG text), with a bounded project
41
+ batch, decoder CPU/memory limits and timeouts. Oversized, malformed, missing or
42
+ unsupported images produce explicit diagnostics.
43
+
44
+ ## Source And Rendered Views
45
+
46
+ The default check inspects image references in published Markdown/HTML source,
47
+ public image metadata and configured content collections. Code examples and
48
+ comments are skipped. The source resolver follows the declared output of
49
+ computation, capture, Mermaid/PlantUML and Vega references, prefers the supported
50
+ author-edited override, and selects maintained language variants using the
51
+ normal default-language fallback.
52
+
53
+ The rendered-output check inspects HTML image references, including `srcset`,
54
+ posters and icon links. It catches assets contributed by layouts or metadata
55
+ that a static source projection cannot resolve. Remote, data-URL and
56
+ fragment-selected references are not fetched or silently certified; inspect a
57
+ local, self-contained output or review the exact rendered view.
58
+
59
+ Findings identify the image path and referring document, include the inspected
60
+ file hash when available, and name the authoritative source for generated
61
+ figures. Repeated references to one asset are grouped.
62
+
63
+ ## Commands And MCP
64
+
65
+ These consumer commands are available from the modular wheel:
66
+
67
+ ```bash
68
+ unaltraweb-mcp --project /path/to/site mcp image-background-check
69
+ unaltraweb-mcp --project /path/to/site mcp image-background-check --source assets/img/map.svg
70
+ unaltraweb-mcp --project /path/to/site mcp image-background-check --source _chapters/en/maps.md
71
+ unaltraweb-mcp --project /path/to/site mcp image-background-check --output-folder _site
72
+ ```
73
+
74
+ The MCP tool is `image_background_check`, and the source report is also available
75
+ at `web://image-backgrounds`. `site_check` includes the source check;
76
+ `html_audit` adds the rendered check; the MCP PDF build returns source-image
77
+ advisories. CLI checks print image warnings to stderr, so the package scaffold's
78
+ normal build still surfaces them when its JSON output is redirected.
79
+
80
+ The reusable deployment workflow runs the packaged native checker before build
81
+ and against the output folder before upload. A native gem installation can use:
82
+
83
+ ```bash
84
+ python /path/to/unaltraweb/scripts/image_background_check.py --project /path/to/site --output-folder _site
85
+ ```
86
+
87
+ The checker requires Pillow, CairoSVG and the system Cairo library. The MCP image
88
+ and native deployment workflow install them. A missing decoder is reported as
89
+ unverifiable. A completed check with transparency warnings exits successfully;
90
+ an invalid inspection request or source inventory returns a nonzero exit status.
91
+
92
+ ## Fixing A Warning
93
+
94
+ Choose a background colour in the authoritative source or export settings. For
95
+ example, Matplotlib exports can set `facecolor` and `transparent=False`, and
96
+ `ggsave` can set `bg`. An SVG can use an opaque full-viewport background shape
97
+ behind its artwork. Check the chosen text/background contrast on web and PDF.
98
+
99
+ Keep the decision with the author: opaque white is one choice, not a forced
100
+ default. Regenerate renderer-owned assets through their factory. Review an
101
+ existing `.edited.svg` or unmanaged image before changing it, and preserve
102
+ original captures and source material. The background check does not establish
103
+ generation freshness, attribution or permission to replace an asset.
@@ -21,7 +21,7 @@ nav_title: Core And Template
21
21
  - It consumes `unaltraweb` as an external dependency.
22
22
  - It contains realistic demo content for `unaltreselfie`, `unaltreprojecte`, `unaltremanual` and `unaltredocs` profiles.
23
23
  - It exercises richer local Docker and browser-test orchestration than the clean package scaffolds.
24
- - The currently published fixture uses `ghcr.io/dosquartsdedocs/unaltraweb:0.3.0`; it should align with the `0.4.0` candidate only after coordinated publication, and mutable `main` remains reserved for maintainer testing.
24
+ - The currently published fixture uses `ghcr.io/dosquartsdedocs/unaltraweb:0.3.0`; coordinated `v0.4.0` is now public, so the fixture can align in a separate reviewed change, while mutable `main` remains reserved for maintainer testing.
25
25
  - It runs Playwright smoke tests and screenshots across profiles, themes and responsive layouts.
26
26
  - It keeps rich demo content out of clean profile scaffolds.
27
27
 
@@ -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.3.0`. Published generated consumers select the higher-level `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.3.0`, which adds the reviewed core and Python control plane. The `v0.4.0` candidate checkout selects matching `0.4.0` images, but downstream consumers must remain on `v0.3.0` until coordinated publication completes. Their Make targets use `/opt/unaltraweb` as a path gem; the RubyGems package remains the optional native Bundler channel. ContExt 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.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.
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,17 +25,37 @@ 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
31
+ 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.
34
+ Unchanged already-published computation and web-capture workers retain their own
35
+ 0.4.0 versions and digests. New/pending worker candidates must still match the
36
+ coordinated release; an old mutable alias cannot qualify for reuse. The selected
37
+ consumer tuple must use a reviewed 0.5.0 core revision and tested PDF worker.
38
+ The PDF worker passed the
39
+ [signed candidate workflow](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/36272762057)
40
+ at source `d857f8c9f5fea90cf450c0b30b4e77a37b541275` and is selected by digest
41
+ `sha256:9e0b3a45753c170b795e9a9d6df61580085c113436beac5bf6c8de69b6562097` in
42
+ both the factory and the consumer tuple. It is already published and tested, so
43
+ 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.
47
+
28
48
  `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.
29
49
 
30
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`.
31
51
 
32
- The selected candidate release is `0.4.0`; `v0.3.0` remains the public distribution until coordinated publication finishes. The BOM reuses immutable compute and web-capture worker digests and selects the published `diavisuals v0.3.1` and `vegavisuals v0.3.1` releases. Current checkouts can be used through `suggested_path`, while immutable release references remain the distribution contract. `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`.
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`.
33
53
 
34
54
  ## Docker-First Hybrid Policy
35
55
 
36
- GHCR is the canonical delivery channel for normal local use. The candidate package scaffold selects `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.4.0`, which must not be adopted by consumers until coordinated publication completes; published `v0.3.0` sites remain supported during preparation. 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.
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.
37
57
 
38
- Factory registration uses a stricter pin. ContExt 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.
58
+ 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.
39
59
 
40
60
  The distribution keeps native channels for interoperability rather than making them Docker prerequisites:
41
61
 
@@ -115,11 +135,11 @@ For that reason:
115
135
  - normal local-runtime improvements should ship through a versioned MCP image; native consumers receive corresponding gem or wheel releases when their package boundary changes;
116
136
  - site repositories can enable Dependabot for Bundler and GitHub Actions, but deploy workflows should remain manual;
117
137
  - breaking changes should be released with migration notes;
118
- - scaffold changes should be rare; generated sites can explicitly dry-run `scaffold_sync`, which updates only unchanged baseline runtime files (including the pull-request template), creates newly managed missing files, reports conflicts, never deletes paths, stages every output, rechecks adopted and unchanged files around the manifest write, rolls the whole transaction back on failure, and commits its manifest last. Generated README prose is site-owned and is not overwritten by synchronization.
138
+ - scaffold changes should be rare; generated sites can explicitly dry-run `scaffold_sync`, which updates unchanged baseline runtime files (including the pull-request template), creates newly managed missing files, and preserves local edits when the upstream file still equals its original baseline. Conflicting local/upstream edits remain blocked. The transaction never deletes paths, stages every output, rechecks adopted, unchanged and preserved files around the manifest write, rolls back on failure, and commits its manifest last. `site_context.update_status` guides the agent's version/update offer; `expected_plan_sha256` binds confirmation to the reviewed proposal. Generated README prose is site-owned and is not overwritten by synchronization.
119
139
 
120
140
  ## Docker Runtime
121
141
 
122
- Release `0.3.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`.
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`.
123
143
 
124
144
  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.
125
145
 
@@ -13,23 +13,23 @@ weight: 140
13
13
  permalink: "/docker-image/"
14
14
  nav_title: Docker Images
15
15
  ---
16
- Release `v0.3.0` currently publishes two core images. Published generated sites select the self-contained MCP/site image for normal local commands:
16
+ Release `v0.4.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.3.0
19
+ ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.4.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.3.0
25
+ ghcr.io/dosquartsdedocs/unaltraweb:0.4.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` candidate source selects matching `unaltraweb:0.4.0` and `unaltraweb-mcp:0.4.0` references. Those tags remain candidate intent, not public installation instructions, until the coordinated receipt, tag, and promotion sequence completes.
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.
31
31
 
32
- ContExt 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.
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
 
34
34
  The GHCR package is kept because it makes the local Docker workflow cheap and repeatable. Publishing is manual. Its unprivileged `preflight` job performs package and source checks without a registry login or Docker build. A default-branch run then crosses three separate credential boundaries:
35
35
 
@@ -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.3.0` pulls have been verified.
61
+ Both core GHCR packages are public, and unauthenticated `v0.4.0` pulls have been verified.
62
62
 
63
63
  ## Computation Images
64
64
 
@@ -190,6 +190,6 @@ ghcr.io/dosquartsdedocs/unaltraweb-web-capture@sha256:0bf1bc67fe63e1440bffe708a1
190
190
 
191
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.
192
192
 
193
- Published `v0.3.0` sites consume `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf:0.3.0`. The candidate source selects `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf:0.4.0`, which must not be adopted until coordinated publication. `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.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.
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,232 @@
1
+ ---
2
+ title: Workspace Path Policies And Consumer Updates
3
+ description: File ownership, Git expectations, PDF recovery and safe consumer migration.
4
+ lang: en
5
+ ref: workspace_path_policies
6
+ profiles:
7
+ - unaltredocs
8
+ documentation_profiles:
9
+ - core-developers
10
+ section: Core Development
11
+ weight: 625
12
+ permalink: "/workspace-path-policies/"
13
+ nav_title: Workspace Path Policies
14
+ ---
15
+
16
+ The discovery manifest `mcp-factory.yml` declares literal consumer-relative
17
+ `workspace_rule.path_policies`, under schema version 1, `binding: consumer` and
18
+ `consumer_root: .`. The central `my-scripts-factory` manager checks these policies
19
+ without launching a provider. `MCP_CONSUMER_WORKSPACE` still carries the absolute
20
+ consumer workspace through the `make -C` stdio launcher; the factory checkout
21
+ does not become the consumer.
22
+
23
+ ## Policy Meaning
24
+
25
+ - `git: ignored` requires actual Git ignore coverage, including inherited parent
26
+ rules, and rejects indexed files anywhere under that path. Merely adding an
27
+ ignore rule does not untrack files.
28
+ - `git: versioned` permits an absent path. An existing path must be indexed and
29
+ not ignored. Stage reviewed source files before checking a freshly created site.
30
+ - `git: consumer` reports the observed Git state without imposing a decision.
31
+ - `cleanup: disposable`, `explicit` and `never` are descriptive metadata, not
32
+ deletion authority. `workspace-check` never performs cleanup. `down` manages
33
+ labelled runtime resources, not the consumer filesystem.
34
+
35
+ Missing optional paths do not enable a feature or create files. An absent ignored
36
+ directory still needs an ignore rule; a trailing-slash rule works before that
37
+ directory exists. In a non-Git directory the manager reports `not_applicable`,
38
+ which is not evidence that a future Git repository is compliant.
39
+
40
+ ## Adopted Literal Paths
41
+
42
+ | Path | Type | Role | Git | Cleanup |
43
+ | --- | --- | --- | --- | --- |
44
+ | `_site` | directory | jekyll-build-output | ignored | disposable |
45
+ | `tmp` | directory | build-staging-and-local-release-evidence | ignored | explicit |
46
+ | `.cache/scimago` | directory | external-bibliometrics-input-cache | ignored | explicit |
47
+ | `.cache/unaltraweb/manual-pdf-publication-intent.json` | file | pdf-publication-recovery-intent | ignored | explicit |
48
+ | `.cache/unaltraweb/manual-pdf-publication.json` | file | pdf-publication-provenance | ignored | explicit |
49
+ | `.cache/unaltraweb/manual-pdf-preview.json` | file | pdf-preview-ownership-receipt | ignored | explicit |
50
+ | `.cache/unaltraweb/manual-pdf-preview.lock` | file | pdf-preview-coordination-lock | ignored | explicit |
51
+ | `.cache/unaltraweb/manual-pdf-preview-recovery` | directory | pdf-preview-retained-recovery-backups | ignored | explicit |
52
+ | `_config.yml` | file | consumer-site-configuration | versioned | never |
53
+ | `.unaltraweb/scaffold.json` | file | managed-scaffold-baseline | versioned | never |
54
+ | `.unaltraweb/docker-mount.sh` | file | managed-docker-mount-helper | versioned | never |
55
+ | `.unaltraweb/computations.yml` | file | optional-consumer-computation-configuration | versioned | never |
56
+ | `.unaltraweb/computations.lock.json` | file | computation-output-provenance | consumer | explicit |
57
+
58
+ `_site` is the normal Jekyll output and can be rebuilt from retained sources,
59
+ inputs and runtimes. It is not the authoritative copy of editorial assets. This
60
+ does not promise byte-identical rebuilds after external inputs or runtimes change,
61
+ nor extend the policy to a custom Jekyll destination. Removing `_site` invalidates
62
+ any site-build evidence that refers to its previous contents.
63
+
64
+ `tmp` mixes Bundler files, render staging and locks, draft PDFs, the site-build
65
+ receipt (`tmp/.unaltraweb/site-build.json`) and local release candidates
66
+ (`tmp/manual-release`). A candidate may be the only retained record of reviewed
67
+ bytes. Review and preserve evidence and finish active operations before deliberate
68
+ cleanup; the entire tree is not unconditionally regenerable. The existing
69
+ consumer `make clean` is a separate explicit operation and refuses to discard
70
+ drafts while a preview receipt remains.
71
+
72
+ Scimago is downloaded from a mutable upstream URL or supplied as a local input.
73
+ Deleting `.cache/scimago` can lose the exact dataset used for bibliometrics. The
74
+ cache's default path is fixed, but scripts can select another input/output path;
75
+ this declaration does not cover such alternatives. Preserve the needed bytes and
76
+ provenance before cleanup. Normal builds do not fetch metrics.
77
+
78
+ `_config.yml` is consumer-owned. The scaffold baseline and Docker mount helper
79
+ are package-managed controls; the baseline is essential to distinguish package
80
+ updates from local edits. Computation configuration is created only for the
81
+ manual profile and stays consumer-owned so it can declare project inputs and
82
+ worker extensions. Its lock records output hashes, source fingerprints and image
83
+ identity; it is generated metadata, not a disposable execution lock. Consumers
84
+ usually version it with generated Markdown/figures, but this rollout does not
85
+ force that choice.
86
+
87
+ ## PDF Recovery Is Not Disposable Cache
88
+
89
+ `src/unaltraweb_mcp/manual_pdf_preview.py` owns the five fixed PDF-state paths:
90
+
91
+ 1. Publication intent records expected hashes before a confirmed copy, allowing
92
+ interrupted publication to be reconciled even if draft artefacts disappear.
93
+ 2. Publication provenance records the identity of deployment products without
94
+ granting preview cleanup ownership over those products.
95
+ 3. The preview receipt records exactly which ignored, untracked copies the
96
+ preview operation owns. Cleanup requires a dry-run, explicit confirmation and
97
+ that receipt's SHA-256, then rechecks identity, hashes, modes and Git state.
98
+ 4. The visible lock and an advisory lock on the project directory coordinate
99
+ operations. Removing the lock marker is not an unlock or recovery procedure.
100
+ 5. Recovery backups preserve originals or concurrent edits when rollback cannot
101
+ safely restore them. Failures can also report retained backups beside an
102
+ output; those configurable locations are not covered by a broad asset policy.
103
+
104
+ Keep receipts, recovery files and their corresponding outputs together until the
105
+ owning operation is reconciled. Use `manual_pdf_preview_clean` for unchanged
106
+ receipt-owned copies, and inspect reported recovery paths when automatic recovery
107
+ fails. Never delete receipts to make an unmanaged collision disappear. This
108
+ adoption does not change confirmation, no-clobber, locking or rollback behavior.
109
+
110
+ ## Provider And Editorial Boundaries
111
+
112
+ The installable dependency closure is `diavisuals`, `vegavisuals`, `unaltraweb`:
113
+ `factory_count: 3`, `dependency_factory_count: 2`. Each manifest keeps its own
114
+ binding and root. Unaltraweb does not redeclare these provider policies:
115
+
116
+ - Diavisuals owns `.cache/diavisuals` (ignored/disposable) and
117
+ `.unaltraweb/receipts/diavisuals.json` (consumer/explicit).
118
+ - Vegavisuals owns `.cache/vegavisuals` (ignored/explicit, including publication
119
+ recovery), `.vegavisuals.yml` (versioned/never), `.vegavisuals.lock.json` and
120
+ `.unaltraweb/receipts/vegavisuals.json` (both consumer/explicit).
121
+
122
+ Receipts prove freshness; their presence in `generated_paths` does not imply
123
+ ignored or disposable state. `site_check` still validates their contents when
124
+ sources require them. Workspace compliance does not establish rendering freshness.
125
+
126
+ The initial selection deliberately leaves these paths without new policies:
127
+
128
+ - PDF and cover destinations and PDF build directories are configurable. The
129
+ runtime checks the actual paths; the manual scaffold renders exact ignore rules
130
+ from configuration. No `assets/pdf` or `assets/img` blanket policy is safe.
131
+ - Computation outputs, rendered diagrams, original capture PNGs, annotated SVGs
132
+ and author-owned edited variants have source-dependent destinations. Preserve
133
+ originals and edited variants and regenerate only through the owning tool after
134
+ reviewing freshness and overwrite requirements. No glob is a literal policy.
135
+ - `.unaltraweb/web-captures.lock.json` remains runtime-managed provenance under
136
+ the existing consumer versioning decision, outside this initial minimal list.
137
+ - Other Jekyll/Quarto caches retain existing ignore rules without a new universal
138
+ cleanup declaration. Neither `assets`, `.cache` nor `.unaltraweb` is classified
139
+ as one disposable tree.
140
+
141
+ ## What Needs Updating
142
+
143
+ | Change | Required action |
144
+ | --- | --- |
145
+ | This discovery-policy adoption | Use a reviewed unaltraweb factory revision containing these declarations and a central manager with path-policy and installable-closure support. |
146
+ | Current v0.4.0 package/image | Already compatible; no rebuild, republish or pin change is required solely for workspace checks. The wheel does not ship the root discovery manifest. |
147
+ | Runtime or package scaffold changes in a later release | Install/select the reviewed package or MCP image containing those changes; reconnect an already-running MCP. Updating a discovery checkout alone does not replace its pinned runtime. |
148
+ | Older or drifted consumer controls | Review `scaffold_sync` against the selected package. Apply only after resolving conflicts deliberately. |
149
+ | Local ignores, tracked cache files, computation locks, renderer receipts or edited outputs | Consumer decision, in its own issue/branch and reviewed diff. No automatic migration or mass regeneration. |
150
+
151
+ The four v0.4.0 profile scaffolds already ignore `_site/`, `tmp/` and `.cache/`.
152
+ That parent rule also covers both renderer caches, including absent directories.
153
+ They create the common versioned controls; only `unaltremanual` creates
154
+ `.unaltraweb/computations.yml`. The optional `.vegavisuals.yml` is not required in
155
+ other profiles. This change leaves package assets, the managed file set and
156
+ `.unaltraweb/scaffold.json` schema/hashes unchanged.
157
+
158
+ ## Existing Consumer Procedure
159
+
160
+ 1. In that consumer's own session, inspect root, branch, status, upstream and
161
+ existing reservations. Run session preflight on a clean short-lived branch.
162
+ Preserve unrelated local work. Record the reviewed discovery commit and
163
+ central manager revision in the integration issue.
164
+ 2. Inspect `Makefile` (`MCP_IMAGE`, `MANUAL_PDF_IMAGE`), `Gemfile`, `Gemfile.lock`,
165
+ `.github/workflows/deploy.yml`, `.unaltraweb/scaffold.json` and
166
+ `distribution_doctor`. Use the published v0.4.0 package/image for the existing
167
+ compatible scaffold, or a later explicitly reviewed release. Do not move the
168
+ immutable v0.4.0 release or install an unpublished branch as a consumer runtime.
169
+ 3. Call `scaffold_sync(dry_run=true)`. It manages exactly `.gitignore`,
170
+ `.unaltraweb/docker-mount.sh`, `.github/CONTRIBUTING.md`,
171
+ `.github/dependabot.yml`, `.github/pull_request_template.md`,
172
+ `.github/workflows/deploy.yml`, `Makefile`, `Gemfile` and `Gemfile.lock`, with
173
+ `.unaltraweb/scaffold.json` written last. Reserve the actual changed paths.
174
+ `_config.yml`, README, AGENTS and editorial files are not synchronized.
175
+ 4. In an MCP with the guided update flow, a customized `.gitignore` or other
176
+ managed file is preserved when the incoming package still equals its recorded
177
+ baseline. Conflicting local/upstream changes prevent the entire apply. The
178
+ original v0.4.0 synchronizer was stricter and reported all differing local
179
+ edits as conflicts. Compare current bytes with the recorded baseline and
180
+ package proposal; preserve local rules and ask the owner which changes to integrate.
181
+ Do not forge baseline hashes, force overwrites, or remove a colliding local
182
+ artefact. Exact current package bytes can be adopted; remaining customizations
183
+ may intentionally remain conflicts. Policy compliance does not require
184
+ overwriting a customized file merely to obtain a clean sync report.
185
+ 5. Where the reviewed plan is conflict-free, call
186
+ `scaffold_sync(dry_run=false, confirm_sync=true, expected_plan_sha256=<reviewed digest>)`
187
+ when using the guided flow. A current v0.4.0 consumer
188
+ needs no scaffold writes for this policy adoption. Inspect Git ignore matches
189
+ and indexed descendants of every ignored policy. Decisions to untrack existing
190
+ files require consumer review; keep the actual files and any recovery evidence.
191
+ 6. Stage only reviewed versioned sources/controls (including an optional Vega
192
+ manifest if present). Run the manager against the absolute consumer path:
193
+
194
+ ```bash
195
+ python3 /path/to/my-scripts-factory/src/bash/mcp_factories/mcp-factory-manager.py \
196
+ workspace-check --dir /path/to/factories --factory unaltraweb \
197
+ --workspace /absolute/consumer --json
198
+ ```
199
+
200
+ Expect all three factories with zero findings/errors. Do not bypass the
201
+ installable dependencies. Inspect each resolved root. The command is read-only;
202
+ it does not stage sources, repair ignores, build images or run provider checks.
203
+ 7. Run `site_check` and resolve blocking findings before `build_site` or
204
+ `make test`. For a local manual PDF review, call
205
+ `manual_pdf_preview_prepare` before a direct MCP build/preview (managed Make
206
+ targets already do this). Review the website/PDF, then dry-run and confirm
207
+ receipt-bound `manual_pdf_preview_clean`. If an unmanaged PDF/cover already
208
+ exists, preserve it and resolve ownership rather than deleting it automatically.
209
+ 8. No artefact needs regeneration merely because discovery metadata changed.
210
+ If actual inputs, sources or runtimes changed, inspect computation/capture and
211
+ provider status and explicitly render only affected outputs under a separate
212
+ accepted reservation. Complete the consumer PR and human review; publication
213
+ remains a separate manual action.
214
+
215
+ ## Maintainer Verification
216
+
217
+ Normal unit tests cover declarations, all four packaged profiles and sync conflict
218
+ preservation. Central-manager integration tests are opt-in so the package does
219
+ not acquire a sibling-checkout runtime dependency:
220
+
221
+ ```bash
222
+ UNALTRAWEB_FACTORY_MANAGER=/path/to/my-scripts-factory/src/bash/mcp_factories/mcp-factory-manager.py \
223
+ UNALTRAWEB_FACTORIES_DIR=/path/to/factories \
224
+ PYTHONPATH=src python3 -m unittest discover -s test -p 'test_workspace_path_policies.py' -v
225
+ ```
226
+
227
+ `test/workspace_consumer_smoke.py` exercises the actual `make -C` Docker stdio
228
+ launcher with an external temporary consumer, all four `new_web` profiles,
229
+ `scaffold_sync`, indexed policy sources, closure snapshots, `site_check` and a
230
+ representative `build_site`. Use its explicit manager/discovery paths and image
231
+ arguments; it never registers an MCP or edits a real consumer. Existing PDF
232
+ preview/recovery unit tests and Docker PDF integrations remain the recovery gates.