unaltraweb 0.7.0 → 0.7.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ed24da568933de15be12350ea7b867a6aa7e14abac71ec303755f5b808e1837
4
- data.tar.gz: a4176d255c14de252144d7669db6479bc43ee033342332cd596870eea1ddf71b
3
+ metadata.gz: 5697f730a670b00edc9d6cda6bb653552470c6c58667d27557e33309203f552c
4
+ data.tar.gz: 1fb32fa043262eca9724aed6dc0184246bc6012f2a6261037f03203ef1265945
5
5
  SHA512:
6
- metadata.gz: 768943c9b012a7e165ab9136d364783203c35caaaae62c2715f95361107f63377dbac30e45252ebeff78b0707d71dd14eb0481cecca18f52b15688c82f4c8c10
7
- data.tar.gz: 49edeb75312f6d45e53db50a55a65f25ddb81f7ad8cc8438c9568ada3c9d699c9c00f0a329ea9b8cc2fb5812b5e48acd254e0e967b659d16650a0ea8612dad16
6
+ metadata.gz: d43c24786b83d17e9cf8cc238eb12227a3d46581fbc550468c95549f9061cd60b6eb4681021855e646929ca41f6b51de850e2db183d956dfd72876b6e48a8a2e
7
+ data.tar.gz: 15c574473f3c71b81b624b08bf4767902deebfc5f0164abc668f43dae6f33f9a0eb8c4a45e1d734a03bd4540b42b81d4e0a77aa8f42ae46566e7cd81cf7af19f
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.7.0
5
- MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.0
6
- MCP_RELEASE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:736c4ddd0a543454e3edaeac2e9cfd97a1279ce472923ac54e326c1281b2ba05
4
+ MCP_RUNTIME_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.7.1
5
+ MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.1
6
+ MCP_RELEASE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:b84cdb404ba7bab5ff0b14fa8a7ee93d7293e829cf32e28ff0dacaa8afff4677
7
7
  MCP_DOCKER_BUILD_NETWORK ?= default
8
8
  INIT_SITE_PROFILE ?= unaltreselfie
9
9
  NEW_WEB_PROFILE ?= unaltreselfie
@@ -40,8 +40,8 @@ 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.7.0
44
- MANUAL_PDF_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed
43
+ DOCKER_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.7.1
44
+ MANUAL_PDF_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:1bb3f2dafd741e96c28639ec1cc8ccaeb81cbaa73e649f787c0b4ef59997bd4b
45
45
  MANUAL_PDF_DEV_IMAGE ?= unaltraweb-manual-pdf:dev
46
46
  MCP_SMOKE_MANUAL_PDF_IMAGE ?= $(MANUAL_PDF_IMAGE)
47
47
  MCP_SMOKE_PROJECT ?=
@@ -45,9 +45,34 @@ For `unaltremanual`, the `latest` channel is a manual-only deployment from the r
45
45
 
46
46
  Clean package scaffolds include a manual GitHub Pages wrapper pinned to a reviewed workflow revision. It has no push deployment trigger: a maintainer runs it only after local checks/renders and human review. The optional integration template retains additional local publishing experiments, but generated sites do not publish from local validation targets.
47
47
 
48
- The `consumer_integration` object in `src/unaltraweb_mcp/component-contract.json` is the single source for the reviewed core revision, workflow path, attested manual PDF image digest, and Vega renderer revision. The scaffold renders that tuple atomically into `Gemfile`, `Gemfile.lock`, and the packaged caller. The caller passes the existing `reviewed_sha` input through to the provider, so the reviewed `main` source is checked independently at both caller and provider boundaries.
49
-
50
- This pin-only integration follows the required M -> D -> B order: D was built from M's permanent identity before the caller recorded either value. Repeat that order for future provider updates; never use `@main` or substitute a mutable/version-tagged image for D.
48
+ The `consumer_integration` object in `src/unaltraweb_mcp/component-contract.json` is the single source for the reviewed core revision, workflow path and revision, attested manual PDF image digest, and Vega renderer revision. The scaffold renders that tuple atomically into `Gemfile`, `Gemfile.lock`, and the packaged caller. From 0.7.1, `site_deploy_workflow_sha` is independent of `core_sha`; older records default to their core pin. The caller passes the existing `reviewed_sha` input through to the provider, so the reviewed `main` source is checked independently at both caller and provider boundaries.
49
+
50
+ The 0.7.1 deployment workflow reads the exact accepted PDF digest and its producer
51
+ commit from the defining provider revision's `deployment_contract` in the BOM.
52
+ It fetches bounded JSON from that immutable provider commit, independently of
53
+ the consumer checkout. It checks the pulled image's revision label against that record, rather
54
+ than assuming the worker and a later workflow revision share a commit. Unknown
55
+ digests fail before Docker access. The reviewed records cover PDF workers 0.5.0
56
+ and 0.6.0; extending them requires a provider review and published-worker tests.
57
+ The records are data in the contract, rather than a release list embedded in the
58
+ workflow program. Release readiness checks the selected workflow's code and own
59
+ records; CI generates a caller and executes the workflow it actually references.
60
+
61
+ A reviewed deployment-only workflow fix can therefore be pinned independently
62
+ of the site's Gem/core revision while retaining an already-accepted PDF worker.
63
+ Update the caller's `uses:` to the immutable corrected workflow commit, review
64
+ that consumer change, and dispatch with the resulting reviewed `main` SHA. The
65
+ existing Gem, PDF and Vega selections need not change for this workflow repair.
66
+ Such a local caller override remains subject to normal scaffold-update conflict
67
+ review. A later package release can incorporate its own reviewed integration tuple.
68
+ Never use `@main` or a mutable/version-tagged image as a substitute for these pins.
69
+
70
+ The 0.7.1 update plan recognizes the exact reviewed one-line issue-86 caller fix
71
+ by both its original baseline hash and current content hash. It lists this as a
72
+ `migrations` entry and requires the normal reviewed plan/atomic apply. Additional
73
+ local edits still produce a conflict; authored content and unrelated files are
74
+ preserved. This lets a known provider repair converge to the next managed tuple
75
+ without treating arbitrary custom workflow code as package-owned.
51
76
 
52
77
  ## Stable manual releases
53
78
 
@@ -25,18 +25,33 @@ The template is the better place to validate gem consumption, centralized styles
25
25
 
26
26
  ## Component Contract
27
27
 
28
- ### 0.7.0 D0 runtime increment
28
+ ### Published 0.7.0 release
29
29
 
30
- The next containing runtime adds [live instance identity and session-scoped
30
+ [**0.7.0**](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.7.0)
31
+ adds [live instance identity and session-scoped
31
32
  resource control]({{ '/live-runtime/' | relative_url }}). Preparation is explicit,
32
33
  launch is pull-never, and startup identity remains distinct from current disk
33
34
  metadata. The owner-tested rendering closure selects Diavisuals 0.5.0 and Vega
34
35
  0.5.1 with exact artifacts; old 0.4.0 static receipts remain integrity-checked.
35
- Diavisuals' separate live-process identity correction still gates the full
36
- managed coordinator closure. Publication and activation evidence belong to the
37
- [D0 owner record](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/d0-runtime-identity.md).
38
-
39
- ### Published 0.6.0 release
36
+ The selected Diavisuals 0.5.0 lacks full live-process identity. The provider's
37
+ [0.6.0 correction](https://github.com/dosquartsdedocs/diavisuals/releases/tag/v0.6.0)
38
+ is published, but remains outside this tested Web combination. Full managed
39
+ coordinator acceptance requires composing-owner validation and a new reviewed
40
+ helper selection.
41
+
42
+ Gem, wheel, base runtime and MCP were produced from
43
+ `b44818c67eecef159f7aa0f825b0416cd511bc43`; receipt integration and tag target
44
+ `9fc84ac7fd01c78c6fe15fe862beb6a5d1633a9e` bind the same-source candidates.
45
+ The post-release checkout launcher selects
46
+ `sha256:b84cdb404ba7bab5ff0b14fa8a7ee93d7293e829cf32e28ff0dacaa8afff4677`.
47
+ Signed-byte D0 acceptance, the retained-letter relocation/rebuild and all four
48
+ populated Bundler roundtrips passed. Public downloads match the receipt.
49
+ The [delivery report](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/owner-closeout-85.md)
50
+ records exact identities and the remaining gates; the
51
+ [D0 owner contract](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/d0-runtime-identity.md)
52
+ defines the native API and lifecycle scopes.
53
+
54
+ ### Previous 0.6.0 release
40
55
 
41
56
  [**0.6.0**](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.6.0)
42
57
  delivers native [retained-letter import]({{ '/retained-documents/' | relative_url }}).
@@ -51,7 +66,7 @@ The PDF worker changes to include complete retained documents and the same
51
66
  integrity checkers used by its controller. Computation, capture and visual
52
67
  companions retain their tested 0.4.0 selections.
53
68
 
54
- The post-release checkout launcher selects published MCP digest
69
+ That release's post-release checkout launcher selected MCP digest
55
70
  `sha256:736c4ddd0a543454e3edaeac2e9cfd97a1279ce472923ac54e326c1281b2ba05`.
56
71
  Signed candidates, protected CI, strict receipt/ancestry gates, registry promotion
57
72
  and Trusted Publishing passed. Anonymous downloads match the receipt. The
@@ -106,25 +121,25 @@ candidate, receipt, tag and package evidence.
106
121
 
107
122
  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`.
108
123
 
109
- The selected public core release is `0.6.0`; 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.
124
+ The selected public core release is `0.7.0`; earlier distributions remain immutable. Its BOM reuses immutable PDF, compute and web-capture worker digests and selects published `diavisuals v0.5.0` and `vegavisuals v0.5.1` 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 `a448cc50a5f511743a6fcfc213baeb9be80f4a27` 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.
110
125
 
111
126
  ## Docker-First Hybrid Policy
112
127
 
113
- ### 0.6.0 component selection
128
+ ### 0.7.0 component selection
114
129
 
115
- The coordinated core identity is **0.6.0**: gem, wheel, base runtime and MCP
130
+ The coordinated core identity is **0.7.0**: gem, wheel, base runtime and MCP
116
131
  images were published together. The installed host launcher and runtime-aware
117
132
  generated Bundler state are included. The PDF worker uses its reviewed, signed
118
- 0.6.0 digest, alongside the 0.4.0 computation/capture workers and visual
119
- companions. A released PDF can be reused only by full digest; new/pending workers
120
- still require the coordinated version. The historical 0.5.0 receipt remains
121
- unchanged. Signed image/package evidence is recorded in the 0.6.0 receipt;
133
+ 0.6.0 digest, alongside the 0.4.0 computation/capture workers and the accepted
134
+ Diavisuals 0.5.0 / Vega 0.5.1 rendering combination. A released PDF can be reused
135
+ only by full digest; new/pending workers still require the coordinated version.
136
+ Earlier receipts remain unchanged. Signed image/package evidence is recorded in the 0.7.0 receipt;
122
137
  promotion and anonymous-download checks passed before the post-release launcher
123
138
  pin was advanced.
124
139
 
125
140
  ### Local delivery
126
141
 
127
- GHCR is the canonical delivery channel for normal local use. The released package scaffold selects `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.6.0`; 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.
142
+ GHCR is the canonical delivery channel for normal local use. The released package scaffold selects `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.0`; 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.
128
143
 
129
144
  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.
130
145
 
@@ -154,7 +169,7 @@ unaltraweb-mcp-docker serve --project /absolute/consumer
154
169
  ```
155
170
 
156
171
  The installed default selects its package's full MCP release image, currently
157
- `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.6.0`. It resolves that selection to the
172
+ `ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.0`. It resolves that selection to the
158
173
  local immutable image ID before executing. The checkout's `MCP_RELEASE_IMAGE`
159
174
  is a separate digest pin advanced only after publication; it is not the installed
160
175
  wheel's default. This avoids sending a new package back to an older MCP while
@@ -299,7 +314,7 @@ For that reason:
299
314
 
300
315
  ## Docker Runtime
301
316
 
302
- Release `0.6.0` 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`.
317
+ Release `0.7.0` 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`.
303
318
 
304
319
  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.
305
320
 
@@ -14,7 +14,8 @@ permalink: /live-runtime/
14
14
  nav_title: Live Runtime
15
15
  ---
16
16
 
17
- The 0.7.0 runtime increment distinguishes the process serving a connection from
17
+ The [published 0.7.0 runtime](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.7.0)
18
+ distinguishes the process serving a connection from
18
19
  the installed package, source checkout and rendering workers. Call
19
20
  `runtime_identity` or read `web://runtime-identity` through that live MCP
20
21
  connection. Both report the same backend instance and startup information.
@@ -83,7 +84,9 @@ observations without running a renderer.
83
84
  Visual helpers are separate MCP processes. Their versions and immutable package
84
85
  selections describe the accepted rendering closure, not their current live
85
86
  instances. The composing controller must obtain each helper's own live identity.
86
- The selected Diavisuals 0.5.0 still requires its separately tracked D0 identity
87
- correction before the entire coordinator closure can be marked managed-ready.
87
+ The selected Diavisuals 0.5.0 lacks full live-process identity. Diavisuals 0.6.0
88
+ publishes the provider correction, but is outside unaltraweb 0.7.0's tested helper
89
+ combination. Composing-owner compatibility validation and a new reviewed selection
90
+ are required before accepting that corrected helper in the managed closure.
88
91
  Existing 0.4.0 static provider receipts remain subject to full integrity checks
89
92
  and do not force regeneration of authored figures during an upgrade.
@@ -6,6 +6,11 @@ Requirements: gaContExt
6
6
  Owner issue: [85](https://github.com/dosquartsdedocs/unaltraweb/issues/85).
7
7
  Coordination: [gaContExt 15](https://github.com/dosquartsdedocs/gacontext/issues/15).
8
8
 
9
+ Delivery: [0.7.0 is published](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.7.0).
10
+ The [signed-byte delivery report](owner-closeout-85.md) supersedes the chronological
11
+ development/candidate state below. It retains the full managed-closure blocker and
12
+ the partial legacy identity gate; publication alone does not close them.
13
+
9
14
  ## Native API mapping
10
15
 
11
16
  The containing 0.7.0 increment adds `runtime_identity` and
@@ -96,7 +101,7 @@ release while a job continues.
96
101
 
97
102
  ## Accepted visual-helper points and remaining closure blocker
98
103
 
99
- The candidate selects the published Diavisuals 0.5.0 and Vega 0.5.1 packages:
104
+ Release 0.7.0 selects the published Diavisuals 0.5.0 and Vega 0.5.1 packages:
100
105
 
101
106
  | Helper | Wheel SHA-256 | Renderer configuration ID |
102
107
  | --- | --- | --- |
@@ -118,10 +123,14 @@ by this source change.
118
123
 
119
124
  The coordinator does not claim to observe another MCP's serving process. Its live
120
125
  identity returns the helper selections and requires their independent connection
121
- observations. **Diavisuals 0.5.0 still lacks the full live-instance identity**;
122
- [Diavisuals 14](https://github.com/dosquartsdedocs/diavisuals/issues/14) is therefore
123
- an external D0 managed-closure blocker. Rendering compatibility alone does not
124
- close that gate or make the whole coordinator dependency graph managed-ready.
126
+ observations. **Selected Diavisuals 0.5.0 lacks the full live-instance identity**.
127
+ [Diavisuals 14](https://github.com/dosquartsdedocs/diavisuals/issues/14#issuecomment-5987114002)
128
+ already records the provider correction in published **0.6.0**; the issue remains
129
+ open for intake. That newer provider is outside unaltraweb 0.7.0's tested helper
130
+ point. The remaining gate is composing-owner compatibility acceptance and a new
131
+ reviewed selection of the corrected helper, followed by independent live
132
+ observations. It is not an unpublished provider implementation. Rendering
133
+ compatibility alone does not make the coordinator dependency graph managed-ready.
125
134
 
126
135
  ## Acceptance and delivery state
127
136
 
@@ -0,0 +1,86 @@
1
+ # Independent PDF worker provenance — issue 86
2
+
3
+ [Owner issue 86](https://github.com/dosquartsdedocs/unaltraweb/issues/86) records
4
+ TIG's failed latest deployment at consumer
5
+ `a87eb4fc7fe58f072413a99356d2465b36d05136`. Its published PDF 0.5.0 was produced
6
+ from `d857f8c9f5fea90cf450c0b30b4e77a37b541275`, whereas its reusable workflow
7
+ was pinned to `02af70001bf8085af860fd57f8d7e75ec96a89c7`. Comparing those two
8
+ different component identities blocked the build before Pages publication.
9
+
10
+ The original gates were re-executed with real published images: canonical 0.5.0,
11
+ 0.5.1 and 0.7.0 tuples fail; the 0.6.0 tuple passes because its two revisions
12
+ happen to coincide. Retained diagnostic evidence is
13
+ `/tmp/opencode/unaltraweb-deploy-86/matrix/evidence.json`, SHA-256
14
+ `8640b7b68456b1bce42b9a0a271fe1c4853fde181eff9b3a130c990bd119142f`.
15
+
16
+ ## Corrected trust binding
17
+
18
+ The reviewed provider workflow now owns these exact digest/producer records:
19
+
20
+ | PDF worker | OCI digest | Producer commit |
21
+ | --- | --- | --- |
22
+ | 0.5.0 | `sha256:9e0b3a45753c170b795e9a9d6df61580085c113436beac5bf6c8de69b6562097` | `d857f8c9f5fea90cf450c0b30b4e77a37b541275` |
23
+ | 0.6.0 | `sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed` | `5cf9817489c8dc47cee726bfe42fe3071cd32b85` |
24
+
25
+ Both references use the fixed repository
26
+ `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf`. The gate first checks the defining
27
+ provider repository and full workflow SHA, rejects an unrecorded digest before
28
+ Docker access, pulls the exact digest and compares its actual revision label
29
+ with the recorded producer. The worker may have been released before the workflow.
30
+ The expected producer is not an input supplied by the consumer, and an inherited
31
+ environment value cannot replace it. Failed pull/inspection stops the step.
32
+
33
+ The deployment's reviewed-main guard, input interface and publication checks are
34
+ unchanged. The gate uses the already-reviewed immutable artifact identity; this
35
+ change does not introduce or claim a new live signature-verification service.
36
+ Release preparation's existing signed-image evidence remains separate.
37
+
38
+ Static workflow policy binds the whole gate, including its records and step
39
+ controls, to reviewed canonical JSON. It rejects disabled/error-tolerant gates
40
+ and refuses a BOM default whose worker has no approved record. A new worker
41
+ requires an explicit provider review, updated policy and published-image tests.
42
+
43
+ ## Regression coverage
44
+
45
+ `test/test_deploy_provenance.py` executes the actual shell blocks from the reusable
46
+ workflow. Unit cases cover earlier legitimate producers, unknown digests with
47
+ plausible labels, mutable/foreign references, missing/wrong labels, a label that
48
+ matches the workflow instead of the worker, attempted expected-revision override,
49
+ foreign/unbound provider authority, pull/inspection failure and reviewed-main
50
+ ref/SHA rejection.
51
+
52
+ The independently gated Docker case executes real pulls and inspections for both
53
+ published workers against a later workflow revision. The ordinary CI distribution
54
+ job must run this case; static policy rejects silently disabling it:
55
+
56
+ ```bash
57
+ UNALTRAWEB_DEPLOY_PROVENANCE_DOCKER=1 PYTHONPATH=test \
58
+ python -m unittest test_deploy_provenance.PublishedDeployProvenanceTests
59
+ PYTHONPATH=src python3 -m unittest discover -s test -p 'test_*.py'
60
+ make workflow-check distribution-check
61
+ git diff --check
62
+ ```
63
+
64
+ Local checks passed 619 Python cases, with 30 optional/environment skips, plus
65
+ the explicitly enabled real-Docker case. The actual image configuration IDs were
66
+ `sha256:c1998dc3345444cb3994ac0cd649ad80ac88dde127dec1dd9f09c719aafe170a`
67
+ for PDF 0.5.0 and
68
+ `sha256:d7e7d3243616270fc9e6eed7f8238c412dbe3d9ffc18d2832d17d66ca630d139`
69
+ for PDF 0.6.0. These tests exercise provenance gates without deploying a consumer.
70
+ Protected PR/integration results and the exact delivery commit are recorded in
71
+ issue 86 after integration.
72
+
73
+ ## Urgent consumer adoption
74
+
75
+ The owner authorized a reviewed workflow-only delivery, independently of a new
76
+ gem/wheel/image release. TIG can retain its approved 0.5.0 Gem/core, PDF digest
77
+ and Vega selection and change only the `deploy.uses` revision in
78
+ `.github/workflows/deploy.yml` to the corrected provider's immutable merge SHA.
79
+ This is a reviewed local caller override; a later scaffold update must preserve
80
+ or explicitly reconcile it rather than resetting it to an older packaged pin.
81
+
82
+ In the TIG checkout, open the integration PR, verify that the content remains at
83
+ its approved baseline, repeat the local publication checks, merge, then dispatch
84
+ with the exact newly reviewed `main` SHA. Confirm the hosted build, Pages site
85
+ and downloadable PDF. The provider gate proof alone does not replace TIG's full
86
+ 311-page manual validation or successful hosted deployment.
@@ -0,0 +1,138 @@
1
+ # Consolidated deployment integration — 0.7.1
2
+
3
+ Owner: [issue 93](https://github.com/dosquartsdedocs/unaltraweb/issues/93), following
4
+ the workflow-only [issue 86 correction](deploy-provenance-86.md). The owner
5
+ authorized implementation, review/integration and gated 0.7.1 publication.
6
+ Current source preparation is distinct from a published distribution; final
7
+ source, receipts, installed-byte evidence and publication are recorded in issue 93.
8
+
9
+ ## One package-owned contract
10
+
11
+ The BOM now carries two additive schema-v1 fields:
12
+
13
+ - `consumer_integration.site_deploy_workflow_sha`, independent of the Gem's
14
+ `core_sha`. Legacy records default to their core revision.
15
+ - `deployment_contract`, with exact `manual_pdf_workers` digest/producer records
16
+ and bounded `caller_migrations` describing reviewed baseline/current hash pairs.
17
+
18
+ The package schema and semantic checks validate repository confinement, unique
19
+ records, nonzero identities, the selected PDF's membership and exact migration
20
+ identities. Existing packages, receipts and the issue-86 workflow pin remain
21
+ unchanged. PDF 0.6.0, computation/capture 0.4.0 and the accepted visual-helper
22
+ combination are reused rather than introducing additional component upgrades.
23
+
24
+ The workflow fetches at most 256 KiB of JSON from its **defining provider commit**
25
+ on the fixed canonical GitHub repository. It does not read a consumer-supplied
26
+ contract or producer SHA. Strict JSON rejects duplicate/non-finite values; records
27
+ have bounded inventory and exact digest/source syntax. Fetch, lookup, pull and
28
+ inspection failures stop publication. A selected immutable digest is checked
29
+ against its recorded producer, not a later workflow commit. Its temporary metadata
30
+ file is invocation-owned and removed on exit.
31
+
32
+ Static policy binds the generic gate code, while approved artifacts live in the
33
+ contract. Ready-source validation resolves the actual workflow Git pin, checks
34
+ its gate and compares its own producer record with the package selection.
35
+ The CI Docker test additionally creates a package caller and executes the
36
+ preflight blocks of the workflow that caller really selects. Checking only the
37
+ current checkout's YAML is insufficient.
38
+
39
+ ## Reviewed hotfix migration
40
+
41
+ Only `.github/workflows/deploy.yml` is eligible for the issue-86 migration:
42
+
43
+ | Identity | SHA-256 |
44
+ | --- | --- |
45
+ | Original package baseline | `a789870542614d5817d30ea4328c7d1ad38d27443c009c68a48ad5aaa3106b8e` |
46
+ | Exact reviewed one-line hotfix | `c632a548d0782867be20a2a52fe03469cf63066b7364bace77fd54a226cb3b18` |
47
+
48
+ Both must match. The dry-run lists `deploy-provenance-86` in `migrations`, proposes
49
+ the new package-generated caller and binds that authorization to `plan_sha256`.
50
+ The existing confinement, CAS rechecks, private staging, rollback and final
51
+ manifest commit remain in force. Any additional author edit remains a conflict;
52
+ removing the migration authority changes the plan hash. This is not a general
53
+ force-sync or semantic rewrite of authored workflow YAML.
54
+
55
+ ## Acceptance stages
56
+
57
+ - Unit/schema/workflow tests cover independent core/workflow pins, legacy metadata,
58
+ invalid or ambiguous records, exact migration, preservation of additional edits,
59
+ plan binding, provider-only contract acquisition and fail-closed network/Docker
60
+ errors.
61
+ - `test/test_deploy_provenance.py` tests actual published PDF workers and a generated
62
+ caller's selected workflow. CI obtains the reviewed source SHA explicitly for
63
+ source-bound metadata access.
64
+ - `test/deployment_integration_smoke.py` uses installed launchers and owned synthetic
65
+ manuals: fresh, populated 0.5.0 upgrade and exact reviewed hotfix. It preserves
66
+ author/cache hashes, applies the reviewed plan, builds PDF/web, probes HTTP and
67
+ executes the exact remotely pinned workflow's source/provenance gates.
68
+ - Final acceptance must use the downloaded same-source wheel and signed MCP
69
+ candidate. The driver does not dispatch Pages or claim a hosted real-manual
70
+ deployment. TIG's authorized deployment is a separate consumer-session proof.
71
+
72
+ The implementation is integrated before the containing source selects its final
73
+ reviewed core/workflow revisions. Candidate components remain pending until that
74
+ selection; release readiness and publication keep their existing strict receipt,
75
+ ancestry, signing and immutable-byte gates.
76
+
77
+ ## Reviewed source selection
78
+
79
+ Implementation `2133b8fa2f668e14d603a36d15584eed63e4386a` is integrated through
80
+ [PR 94](https://github.com/dosquartsdedocs/unaltraweb/pull/94) at
81
+ `2ff27f27c274eb09b2c53ef8bd374f333702d8ee`. PR CI `37526811887` and CodeQL
82
+ `37526811747` passed, including actual provider-record acquisition and generated
83
+ caller provenance checks. The review is agent-attributed.
84
+
85
+ The containing candidate now selects this integration for both independent
86
+ core/workflow fields and marks gem, wheel, runtime and MCP ready for same-source
87
+ candidate preparation. The selected workflow's own contract records the reused
88
+ PDF 0.6.0 producer correctly; no worker version change is needed.
89
+
90
+ Local source validation passed 629 cases with 31 optional/environment skips,
91
+ fresh-wheel and owned-image MCP checks/smoke, docs and prose checks. The installed
92
+ development new/upgrade/hotfix manual proof is retained at
93
+ `/tmp/opencode/unaltraweb-071-93/local-integration/evidence.json`, SHA-256
94
+ `d98c0fb56d2b74839a7132cc9dc7ab3f65a9802087837af1a13070a51316a14a`.
95
+ That development proof still used the earlier reviewed workflow pin; final
96
+ signed-candidate acceptance must exercise the now-selected integration above.
97
+
98
+ ## Final-byte gate: retained-document worker closure
99
+
100
+ The first candidates from `b7ec1d7a139c65b3b0b88699cdbeb19080f13be1` passed normal
101
+ manual upgrades but failed retained-Carta freshness with the reused PDF 0.6.0.
102
+ The manifest fingerprints `artifact_imports.CHECKER_FILES`, including the changed
103
+ distribution module and component schema. Successful PDF generation alone was
104
+ not sufficient: the old worker and new controller calculated different identities.
105
+ Those first core candidates are retained diagnostic evidence and are not promoted
106
+ as the 0.7.1 release.
107
+
108
+ The signed PDF specialization already built/tested by run `37530306398` contains
109
+ the matching 0.7.1 checker closure:
110
+ `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:1bb3f2dafd741e96c28639ec1cc8ccaeb81cbaa73e649f787c0b4ef59997bd4b`.
111
+ Its configuration ID is
112
+ `sha256:618163d3f924439792b2306617bd9612f566c5881166102fa544b4e782d569fa`,
113
+ its producer revision is the first candidate source above and its native package
114
+ reports 0.7.1. The changed checker files match the controller byte for byte.
115
+
116
+ A local controller overlay selecting only that exact worker passed the complete
117
+ Carta import, copied-producer retirement, receiver relocation and forced PDF
118
+ rebuild. Both 11-page PDFs have hash
119
+ `eb693ced023efafe36a926dd38a1bf1c85399a1b114551cc0ff32e652144c496`; original Carta
120
+ bytes remain unchanged. Diagnostic evidence:
121
+ `/tmp/opencode/unaltraweb-071-93/pdf071-carta-probe/evidence.json`, SHA-256
122
+ `c076f988e43ddb474132e58f5027931085bd734242757b84fb50289ef68cde25`.
123
+ The overlay is not a signed final MCP identity.
124
+
125
+ The worker record is integrated before a follow-up selection pins its containing
126
+ workflow and PDF. Core components return to pending during this preparation.
127
+ Ready-source CI now requires the exact selected core, controller and PDF worker
128
+ to agree on every retained-document checker file. This catches this class of
129
+ incompatibility before final publication; the final signed core candidates must
130
+ still repeat the complete composed acceptance.
131
+
132
+ The producer record and checker-closure regression were integrated through
133
+ [PR 96](https://github.com/dosquartsdedocs/unaltraweb/pull/96) at
134
+ `3332e0b93933f12317e05f1ce8d38ce80046feab`. This is the final reviewed core/workflow
135
+ selection. The tuple selects the verified PDF specialization above as 0.7.1,
136
+ published by its immutable digest, and the four core components return to ready.
137
+ Their new same-source candidates replace the rejected first core tuple in the
138
+ eventual release receipt. No earlier release or worker is overwritten.
@@ -1,9 +1,10 @@
1
1
  # MCP Contract
2
2
 
3
- The D0 additions require a containing 0.7.0 runtime. Their pinned requirements,
3
+ The D0 additions ship in the published 0.7.0 runtime. Their pinned requirements,
4
4
  exact API mapping, lifecycle scopes and external helper-identity blocker are
5
5
  documented in [the owner contract](d0-runtime-identity.md). A source descriptor
6
- does not upgrade an already-running 0.6.0 connection.
6
+ does not upgrade an already-running 0.6.0 connection. Exact public identities and
7
+ installed acceptance are recorded in [the delivery report](owner-closeout-85.md).
7
8
 
8
9
  `unaltraweb` exposes one global, on-demand stdio MCP server for website workspaces. Every client session starts an independently named Dockerized MCP process and mounts its current consumer project at `/workspace` and at its canonical host path. Stable factory, role, and project labels preserve project-scoped lifecycle control without forcing concurrent sessions to share a deterministic container name. The image includes both FastMCP and the Jekyll runtime, so the host does not need Python, the optional `mcp` package, Ruby, or Bundler.
9
10
 
@@ -37,8 +38,8 @@ it to an image ID before execution. The source checkout's digest pin is separate
37
38
  it advances only after a new receipt exists. Explicit `--image` (or the console
38
39
  adapter's `UNALTRAWEB_MCP_IMAGE`) permits a reviewed immutable selection.
39
40
 
40
- The post-release checkout pin selects published 0.6.0 MCP digest
41
- `sha256:736c4ddd0a543454e3edaeac2e9cfd97a1279ce472923ac54e326c1281b2ba05`.
41
+ The post-release checkout pin selects published 0.7.0 MCP digest
42
+ `sha256:b84cdb404ba7bab5ff0b14fa8a7ee93d7293e829cf32e28ff0dacaa8afff4677`.
42
43
  Existing processes keep their running image until clients reconnect. Site build
43
44
  defaults and customized Makefiles remain separate, explicitly reviewed selections.
44
45
 
@@ -0,0 +1,269 @@
1
+ # unaltraweb 0.7.0 D0 delivery closeout
2
+
3
+ Published **2026-10-05 21:45:13 UTC**:
4
+ [v0.7.0](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.7.0).
5
+ Owner: [issue 85](https://github.com/dosquartsdedocs/unaltraweb/issues/85).
6
+ Coordination: [gaContExt 15](https://github.com/dosquartsdedocs/gacontext/issues/15).
7
+ Requirements: gaContExt `5634ea2e3e42122bb365992dfca9f248feb89dec`.
8
+ This report supersedes the chronological candidate state in the
9
+ [native API contract](d0-runtime-identity.md).
10
+
11
+ ## Review and exact source
12
+
13
+ The owner explicitly authorized the complete review/PR/integration, gated
14
+ publication and separate post-release checkout pin. Work used only
15
+ `/home/benizar/git/unaltraweb`, ordinary serial branches and synthetic consumers.
16
+ Existing releases, authored state and unrelated client registrations were retained.
17
+
18
+ | Role | Revision / evidence |
19
+ | --- | --- |
20
+ | Reviewed D0 implementation | `0c87e8c276e58ac9c747833df69cdb439aa6132b` |
21
+ | Integrated core selected by consumers | `216ab2e8b6b8b45a5bb7da0a54bffd10edee895d`, [PR 87](https://github.com/dosquartsdedocs/unaltraweb/pull/87) |
22
+ | Core selection commit | `2881a37dd6e5071d71c30cb44aa9af6faba5e886` |
23
+ | Final artifact-producing source | `b44818c67eecef159f7aa0f825b0416cd511bc43`, [PR 88](https://github.com/dosquartsdedocs/unaltraweb/pull/88) |
24
+ | Receipt-only child | `6dc13638c49bfb53a1c456e9e6b30aec7b3fd713` |
25
+ | Receipt integration / tag target | `9fc84ac7fd01c78c6fe15fe862beb6a5d1633a9e`, [PR 89](https://github.com/dosquartsdedocs/unaltraweb/pull/89) |
26
+ | Annotated tag object | `28a2a40b4b633be2fefb3f1c753cf95db1c7bdf6` |
27
+ | Reviewed post-release pin / report | `7f9ce5b3bd844aed3a820c98f9712b7cfc8c23ea` |
28
+ | Post-release integration | `833c5548ff01801097ddd56114d9039fd3914a43`, [PR 90](https://github.com/dosquartsdedocs/unaltraweb/pull/90) |
29
+
30
+ Review records are explicitly agent-attributed, not human approval. The receipt
31
+ integration's first parent is the artifact source; its first-parent diff contains
32
+ only `release-candidates.json`. Native package authorization, exact staging,
33
+ strict distribution/publication-ref checks and annotated-tag verification passed
34
+ before privileged publication. These release checks apply to the receipt/tag
35
+ revision, not later ordinary post-release commits.
36
+
37
+ ## Receipt, packages and images
38
+
39
+ [Tagged receipt](https://github.com/dosquartsdedocs/unaltraweb/blob/v0.7.0/release-candidates.json):
40
+ schema 1, source `b44818c67eecef159f7aa0f825b0416cd511bc43`, SHA-256
41
+ `92b4feafbf822ff5b0d9fc6534f963e68c2a28a875d4e2e841c051e7c619e7dc`.
42
+ It contains exactly the four components marked `ready` in the source BOM.
43
+
44
+ | Component | Artifact / repository | SHA-256 / OCI index digest |
45
+ | --- | --- | --- |
46
+ | Gem | `unaltraweb-0.7.0.gem` | `1f4c71fc03bc3025018873eae73f7a2274e46b87ac678805e4150b8351b9ff0c` |
47
+ | Wheel | `unaltraweb_mcp-0.7.0-py3-none-any.whl` | `3c9cd477e8c2fa0f69c1309c9302b110b73032600e8cf040c4818169863dd868` |
48
+ | Base runtime | `ghcr.io/dosquartsdedocs/unaltraweb` | `sha256:ce67aa8fb90899e3c770c4ec8952b760cc8cafb3ed203e8e15266a9623bb3d31` |
49
+ | MCP | `ghcr.io/dosquartsdedocs/unaltraweb-mcp` | `sha256:b84cdb404ba7bab5ff0b14fa8a7ee93d7293e829cf32e28ff0dacaa8afff4677` |
50
+
51
+ Both OCI aliases `0.7.0` and `v0.7.0` were inspected anonymously and match these
52
+ digests. Local Linux/amd64 configuration IDs are distinct:
53
+
54
+ - Runtime: `sha256:beec5459bc7aa159af428fbad5d14a4527f3143e5062ec305a00619c31aae706`.
55
+ - MCP: `sha256:b03e463343abcd0d5891f68ec423256f970d7c1fb35dc875e089e0f745cfe39a`.
56
+
57
+ Their revision labels equal the artifact source. The image workflow verified
58
+ GitHub-signed provenance, signer workflow, source revision and labels before
59
+ executing the exact candidates. Semver promotion reverified those identities and
60
+ reused the tested manifests without rebuilding.
61
+
62
+ The package workflow artifact is `11329540867`, named
63
+ `unaltraweb-0.7.0-b44818c67eecef159f7aa0f825b0416cd511bc43`; its archive digest is
64
+ `sha256:9af51fb8447cf77691ffd362a752b247a9a1ee45a351f44b8de8ac60d62317c9`.
65
+ The publisher authorized the exact successful run, source and inventory, then
66
+ verified/staged the recorded hashes. Separate OIDC jobs published those bytes.
67
+ Anonymous PyPI/RubyGems metadata and downloads match them. Downloaded GitHub
68
+ Release assets also pass `SHA256SUMS`, whose SHA-256 is
69
+ `4abdefd44dd6cce44262fd19e224a54ca7a1d1b7ada66071d5b737d94f9270ab`.
70
+
71
+ ## Reused workers and accepted helpers
72
+
73
+ The selected PDF remains the published, signed 0.6.0 specialization:
74
+ `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed`.
75
+ Its configuration ID is
76
+ `sha256:d7e7d3243616270fc9e6eed7f8238c412dbe3d9ffc18d2832d17d66ca630d139`.
77
+ It is `released`, outside the four-component receipt. The source-bound workflow
78
+ also tested PDF candidate
79
+ `sha256:d6d866cd16eab156e7dc3fea2fd7e649d8b91dca2916b45cd5c2218184d5928b`;
80
+ that verification-only candidate received no 0.7.0 semver promotion and is not
81
+ the selected worker.
82
+
83
+ Computation and capture keep their 0.4.0 immutable BOM references. The retained D0
84
+ observation reports Python compute as prepared; R compute and web capture were
85
+ locally missing and remained explicitly `missing`, without fallback. This
86
+ acceptance executes web/manual-PDF work, not every optional computation/capture
87
+ workflow. An adapter enabling those features must prepare and verify their exact
88
+ workers separately.
89
+
90
+ | Accepted helper | Wheel SHA-256 | Renderer configuration ID |
91
+ | --- | --- | --- |
92
+ | Diavisuals 0.5.0 | `f52e20f20f1fb3a2418f07adb8d6a68a5567d0c321fb7c0ccc0f4db04917b96b` | `sha256:5a6887b372a0e1c386a7b54981d11ae1910215baeb6a12dfd0706b3e85ef0846` |
93
+ | Vega 0.5.1 | `5aba4f267a37179c520b3cd164e1cec62ac5561872aa33b069cce73442dc52b1` | `sha256:695125943d0fbc3aa7c877babb9a11a6501bbc7ac265b0975bb5657c60439d98` |
94
+
95
+ Native selection uses Diavisuals `--runtime-image` / `--runtime-expected-id` and
96
+ Vega `--renderer-image-id`. Actual Mermaid, PlantUML, Vega-Lite/CSV and Vega renders
97
+ passed receipt verification, tamper refusal and consumer relocation. Existing
98
+ renderer aliases were unchanged. Exact 0.4.0 static receipt compatibility retains
99
+ all input/output/request integrity checks; no continuous version range is inferred.
100
+
101
+ ## Live identity and installed acceptance
102
+
103
+ The actual serving process provides `runtime_identity` and
104
+ `web://runtime-identity`; both agreed on the backend instance. Native profile
105
+ `unaltraweb-docker-stdio-v1` uses one connection per backend, one operation at a
106
+ time, explicit drain and scoped orphan recovery. Host commands `session-status`
107
+ and `reap-session` consume the retained consumer/session/container tuple.
108
+
109
+ The initial accepted backend instance was `400244b6784c46498aadd3ec3b9c088f`, with
110
+ inner PID 7 in `pid:[4026533734]`, start ticks `65541450`, Python 3.13.5 and
111
+ executable `/usr/bin/python3`. Container
112
+ `3feb725c68984e69fe208d56bdf06ec2dfcff4d43f1071045ebc0eadf3779ffe` had daemon init
113
+ PID `3938960`; these PIDs belong to different namespaces. The canonical consumer
114
+ binding was `/tmp/opencode/unaltraweb-d0-85/candidate-d0-proof/consumer A`.
115
+ Reconnection produced instance `9c9d94e47c324be89abff5e80defb024` while the second
116
+ consumer retained instance `413e89f4ebd34e5d8570b1db6a8360af`.
117
+
118
+ The installed engine root was `/usr/local/lib/python3.13/dist-packages/unaltraweb_mcp`.
119
+ Loaded version 0.7.0 and startup code fingerprint
120
+ `5fdfb154f82d01bb5dcc5a35d74ba2f384b36e60a5111b63831b6216adfb8996` remained fixed
121
+ when metadata in the disposable container overlay changed to 99.0.0. Current
122
+ bytes reported drift; the prepared image was unchanged. Observed canonical
123
+ component-contract hash:
124
+ `d2cddda50780f00ec3af47826a93341e014d4811146195ed09a9bf1ee5fcdf81`;
125
+ profile hash:
126
+ `6c9305143f2f5e3dee831f3d5bf2b5413e51f24e3f28310fa21019c645532481`.
127
+ Selection hashes additionally bind each consumer/worker tuple and are retained in
128
+ the evidence. These observations are not permanent process attestations.
129
+
130
+ `test/d0_runtime_smoke.py` passed all eight stages against the downloaded CI wheel
131
+ and signed MCP: reconnect/scope, loaded-versus-disk, busy drain, backend-crash
132
+ recovery, offline launch, explicit nested daemon mapping, wrong worker and missing
133
+ worker. Wrong/missing controller images were also refused. A real PDF job was
134
+ observed **busy after backend death**; recovery waited until it became eligible,
135
+ then proved resource absence while another live backend remained connected.
136
+ EOF/drain released only the retired session's resources.
137
+
138
+ The real 0.6.0 → 0.7.0 → 0.6.0 roundtrip preserved authored files and old generated
139
+ cache entries. The unrelated registration sentinel retained SHA-256
140
+ `2705c6065bbc5665798be533b1057070b6efeae289cab3e800579cb6b5608afb`.
141
+ The historical 0.6.0 process lacks live identity and remains an explicitly
142
+ **partial** point, not a second D0-capable release.
143
+
144
+ ## Retained Carta and populated Bundler regressions
145
+
146
+ `test/artifact_import_smoke.py` consumed the authenticated published Carta packet.
147
+ Bundle hash `aeaa757ee1be19bfe56dc9af8dd1178032929b4a2bec2dad2ebb621b158ad999`
148
+ and the 12-file seal remain intact. The mapping from `payload/output/letter.pdf`
149
+ to `assets/documents/carta.pdf` retains original PDF hash
150
+ `4a661740a18fe1cf75b84aa0d8532511fd105eb5484a5af700e11e8e30828ea4`.
151
+ Integration record hash:
152
+ `995e213e9c5677763809b4d108b84882e1821be58796e0823b8260c22f891a18`.
153
+
154
+ The copied producer and incoming tree were removed, author prose survived
155
+ reimport, and the receiver moved before native/generic checking and a forced PDF
156
+ rebuild. Web/HTTP passed at both locations. Both 11-page PDFs have SHA-256
157
+ `026552039659771d73a26875dc628c5dbccb8da2d4c32bcf0a199929efdd60e2`; the unchanged
158
+ letter appears on page 10. Generic verification confirmed one bundle, one mapping
159
+ and 14 files; the native checker also bound the chapter and rendered page.
160
+
161
+ `test/bundler_transition_smoke.py` passed all four profiles using actual immutable
162
+ 0.4.0, unpatched 0.5.0 and new 0.7.0 MCP references. The known failure was
163
+ reproduced on a separate copy. Each 0.7.0 activation and return to 0.4.0 passed
164
+ two builds and a preview. All six author/cache files kept their hashes, with no
165
+ cache clearing. `test/published_companion_smoke.py` passed with the published
166
+ helper wheels and explicit renderer IDs above. The downloaded CI gem passed
167
+ `scripts/test_gem_build.py:inspect_gem`, including isolated native helper closure.
168
+
169
+ ## CI and retained evidence
170
+
171
+ | Gate | Successful run |
172
+ | --- | --- |
173
+ | Implementation PR CI / CodeQL | [37271200816](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37271200816) / [37271200817](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37271200817) |
174
+ | Core selection PR CI / CodeQL | [37272201763](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37272201763) / [37272201726](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37272201726) |
175
+ | Final artifact source CI / CodeQL | [37272717370](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37272717370) / [37272717381](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37272717381) |
176
+ | Signed candidate image build/test | [37273192732](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37273192732) |
177
+ | Package preparation | [37273195884](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37273195884) |
178
+ | Receipt PR CI / CodeQL | [37371882737](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37371882737) / [37371882776](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37371882776) |
179
+ | Receipt integration CI / CodeQL | [37375549493](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37375549493) / [37375549627](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37375549627) |
180
+ | Tag CI | [37376786630](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37376786630) |
181
+ | Semver image promotion | [37377435437](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37377435437) |
182
+ | PyPI/RubyGems Trusted Publishing | [37377438226](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37377438226) |
183
+ | Post-release PR CI / CodeQL | [37379728022](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37379728022) / [37379728286](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37379728286) |
184
+ | Post-release integration CI / CodeQL | [37380436187](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37380436187) / [37380436184](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37380436184) |
185
+
186
+ Two first-attempt receipt PR jobs were not acquired by hosted runners and ran no
187
+ steps. Their retry passed without source changes; original attempts remain in
188
+ the local evidence. The local source suite passed 608 Python cases, with 30
189
+ optional/environment skips. No failed job was bypassed for merge or publication.
190
+
191
+ Evidence root: `/tmp/opencode/unaltraweb-d0-85/`.
192
+
193
+ | Retained result | SHA-256 |
194
+ | --- | --- |
195
+ | `image-evidence/tested-images.json` | `6c38a1d08511d0cb6554905bc236de58a9f594b255553361d36e6caa4622335d` |
196
+ | `candidate-d0-proof/evidence.json` | `e8140ef8cf47e4329f7691b8a3733377a17269b83c2cf2e9b444c94ce22621f6` |
197
+ | `candidate-carta-proof/evidence.json` | `c1b12f80b1a3c0d31a83fa015f050f0897923ef578ecac9c20f95e4acaa6fca0` |
198
+ | `candidate-bundler-proof/evidence.json` | `8206e1a9e4a88123390dad30ba314d0b2fa00820a5af426164f060050be3ab4d` |
199
+ | `candidate-helpers-proof/evidence.json` | `df994ccd8afaff45a7e3cfa9b6a29b650c9d01d63db2c9c36e59c31834273473` |
200
+ | `published-packages/verified.json` | `e892bbb22c35ea3eef3b2abbbd6351e4a290e76d322c91ac3de6fb212965909f` |
201
+ | `public-images.json` | `f123c2dc096405bde004cfd6cbce206a0f56925f436731e575830cf111d26314` |
202
+ | `post-pin-proof/evidence.json` | `0944b95eec8d0e1103f4895595c77780d27ebc1a3e64626f421b960be8efd144` |
203
+
204
+ ## Public installation and checkout selection
205
+
206
+ A fresh public-wheel venv passed default `prepare`, `check` and real stdio
207
+ `smoke`, with the expected MCP configuration ID. That public installation also
208
+ rechecked the relocated Carta source/rendered mapping. The public gem installed
209
+ in an isolated gem home and activated as 0.7.0 with the runtime's existing Ruby
210
+ dependencies, including Ruby's default gem paths; this is not a network-fresh
211
+ dependency installation claim.
212
+
213
+ The separate `chore/85-pin-published-mcp-0.7.0` source change selects the published
214
+ digest in Make/bootstrap and updates its existing pin regression and current docs.
215
+ It does not alter the published BOM, receipt, tag or artifact bytes. PR 90 and its
216
+ integration passed protected CI; the resulting main checkout was clean and
217
+ synchronized. The later helper-intake clarification is documentation-only.
218
+
219
+ The actual `MCP_CONSUMER_WORKSPACE=… make mcp-stdio` transport started a synthetic
220
+ consumer with live instance `2ebdbd20c32649c48bf309dc469f2c8b`. Tool/resource
221
+ identity agreed, loaded 0.7.0 and the published image matched, and drain/close
222
+ followed by exact retained-tuple inspection confirmed resource release.
223
+ `make mcp-build` and the bootstrap's `--check` selected that public image directly.
224
+
225
+ Post-pin local checks passed 608 Python cases (579 passed, 29 optional skips),
226
+ `make distribution-check workflow-check`, the fresh `make wheel-check`, prose
227
+ checks, `editorial-publication-check` and `git diff --check`. The prose checker
228
+ reported only existing informational sentence-length cues, not blocking findings.
229
+ The source Make targets were exercised with independently owned development names:
230
+
231
+ ```bash
232
+ make mcp-check mcp-smoke \
233
+ MCP_RUNTIME_IMAGE=unaltraweb-d0-85-runtime:post-pin \
234
+ MCP_IMAGE=unaltraweb-d0-85-mcp:post-pin \
235
+ MANUAL_PDF_DEV_IMAGE=unaltraweb-d0-85-pdf:post-pin \
236
+ MCP_SMOKE_MANUAL_PDF_IMAGE=ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed
237
+ make docs-build \
238
+ DOCKER_IMAGE=ghcr.io/dosquartsdedocs/unaltraweb@sha256:ce67aa8fb90899e3c770c4ec8952b760cc8cafb3ed203e8e15266a9623bb3d31
239
+ ```
240
+
241
+ Both commands passed. Development outputs remain separate from the signed
242
+ artifact acceptance and did not replace public semver images or retained caches.
243
+
244
+ ## Remaining gates and scope
245
+
246
+ **The complete coordinator dependency graph is not declared managed-ready.**
247
+ Selected Diavisuals 0.5.0 lacks full serving-process identity. The
248
+ [provider return in Diavisuals 14](https://github.com/dosquartsdedocs/diavisuals/issues/14#issuecomment-5987114002)
249
+ records that **Diavisuals 0.6.0 already published the native correction on
250
+ 2026-10-05 at 02:25:02 UTC**, from `1c2dd8c8138e27bcdb1b0fee1fd51e1d057130e3`.
251
+ Its live mapping is `server_identity` / `diavisuals://server/identity`, with its
252
+ own lifecycle. The open issue tracks acceptance/intake, not missing publication.
253
+
254
+ Unaltraweb 0.7.0 was tested and published with 0.5.0. The outstanding composition
255
+ gate is therefore **owner acceptance of the corrected helper and a new reviewed
256
+ selection**, not another claim that the provider correction has yet to ship.
257
+ The hub cannot widen the published 0.7.0 helper pin from metadata alone. It must
258
+ also observe each independent helper process, prepare feature-specific workers
259
+ and accept the native adapter before activation. This clarification does not
260
+ change the released BOM or count Diavisuals 0.6.0 as tested Web compatibility.
261
+
262
+ The acceptance platform is Linux/amd64 and the claimed backend profile is Docker
263
+ stdio, one connection per instance. Shared HTTP backend reattachment and a fully
264
+ D0-capable two-release roundtrip are not claimed. Arbitrary direct controller
265
+ layouts remain [issue 31](https://github.com/dosquartsdedocs/unaltraweb/issues/31);
266
+ only canonical host and explicitly mapped nested launchers were proved. Retained
267
+ Carta coverage is the published English one-page leaf, not Diapora composition.
268
+ Real manuals, author artifacts and existing client registrations were not migrated.
269
+ Already-running clients retain their loaded runtime until explicit reconnection.
@@ -290,7 +290,7 @@ def main() -> int:
290
290
  raise RuntimeError(f"generated {profile} Gemfile does not use the reviewed core revision")
291
291
  if f'revision: {integration["core_sha"]}' not in lockfile:
292
292
  raise RuntimeError(f"generated {profile} lockfile does not use the reviewed core revision")
293
- if f'uses: {integration["site_deploy_workflow"]}@{integration["core_sha"]}' not in deploy:
293
+ if f'uses: {integration["site_deploy_workflow"]}@{integration["site_deploy_workflow_sha"]}' not in deploy:
294
294
  raise RuntimeError(f"generated {profile} deploy caller does not use the reviewed core revision")
295
295
  if f'manual-pdf-image: "{integration["manual_pdf_image"]}"' not in deploy:
296
296
  raise RuntimeError(f"generated {profile} deploy caller does not use the reviewed PDF image")
@@ -15,7 +15,7 @@ Managed mode requires an immutable reference or an expected full image ID.
15
15
  USAGE
16
16
  }
17
17
 
18
- image="${UNALTRAWEB_MCP_IMAGE:-ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:736c4ddd0a543454e3edaeac2e9cfd97a1279ce472923ac54e326c1281b2ba05}"
18
+ image="${UNALTRAWEB_MCP_IMAGE:-ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:b84cdb404ba7bab5ff0b14fa8a7ee93d7293e829cf32e28ff0dacaa8afff4677}"
19
19
  project="${MCP_CONSUMER_WORKSPACE:-${UNALTRAWEB_PROJECT:-}}"
20
20
  operation=serve
21
21
  expected_image="${UNALTRAWEB_EXPECTED_IMAGE_ID:-}"
@@ -4,6 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import argparse
7
+ import hashlib
7
8
  import json
8
9
  import os
9
10
  import re
@@ -39,7 +40,7 @@ from unaltraweb_mcp.distribution import ( # noqa: E402
39
40
  is_mutable_reference,
40
41
  validate_component_contract,
41
42
  )
42
- from scripts.validate_workflows import load_workflow_text, reusable_deploy_input_errors # noqa: E402
43
+ from scripts.validate_workflows import DEPLOY_PDF_PROVENANCE_POLICY_SHA256, load_workflow_text, reusable_deploy_input_errors # noqa: E402
43
44
 
44
45
 
45
46
  def load_yaml(path: Path) -> dict[str, Any]:
@@ -88,6 +89,21 @@ def component_version_errors(contract: dict[str, Any]) -> list[str]:
88
89
  return errors
89
90
 
90
91
 
92
+ def selected_deployment_errors(contract: dict[str, Any], workflow: dict[str, Any], provider_contract: dict[str, Any]) -> list[str]:
93
+ """Release readiness binds the called workflow's code and data, not local YAML."""
94
+ errors = []
95
+ steps = workflow.get("jobs", {}).get("build", {}).get("steps", [])
96
+ step = next((row for row in steps if row.get("name") == "Verify manual PDF image provenance"), {})
97
+ if hashlib.sha256(json.dumps(step, sort_keys=True, separators=(",", ":")).encode()).hexdigest() != DEPLOY_PDF_PROVENANCE_POLICY_SHA256:
98
+ errors.append("selected deployment workflow does not contain the reviewed contract-driven provenance gate")
99
+ reference = contract["consumer_integration"]["manual_pdf_image"]
100
+ expected = [row for row in contract.get("deployment_contract", {}).get("manual_pdf_workers", []) if row.get("reference") == reference]
101
+ actual = [row for row in provider_contract.get("deployment_contract", {}).get("manual_pdf_workers", []) if row.get("reference") == reference]
102
+ if len(expected) != 1 or actual != expected:
103
+ errors.append("selected deployment workflow's producer record differs from the package's PDF identity")
104
+ return errors
105
+
106
+
91
107
  def validate(root: Path = ROOT) -> list[str]:
92
108
  errors: list[str] = []
93
109
  contract = distribution_contract()
@@ -125,6 +141,11 @@ def validate(root: Path = ROOT) -> list[str]:
125
141
  errors.append(f"component contract schema validation failed: {exc}")
126
142
  errors.extend(f"component contract semantic validation failed: {error}" for error in component_contract_semantic_errors(contract))
127
143
  core_sha = str(contract["consumer_integration"]["core_sha"])
144
+ workflow_sha = str(contract["consumer_integration"].get("site_deploy_workflow_sha", core_sha))
145
+ workflow_ancestor = subprocess.run(["git", "merge-base", "--is-ancestor", workflow_sha, "HEAD"], cwd=root,
146
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
147
+ if workflow_ancestor.returncode != 0:
148
+ errors.append("consumer integration workflow SHA must be an ancestor of the current source")
128
149
  core_object = subprocess.run(
129
150
  ["git", "cat-file", "-e", f"{core_sha}^{{commit}}"],
130
151
  cwd=root,
@@ -145,7 +166,7 @@ def validate(root: Path = ROOT) -> list[str]:
145
166
  if core_ancestor.returncode != 0:
146
167
  errors.append("consumer integration core SHA must be an ancestor of the current source")
147
168
  pinned_workflow = subprocess.run(
148
- ["git", "show", f"{core_sha}:.github/workflows/site-deploy.yml"],
169
+ ["git", "show", f"{workflow_sha}:.github/workflows/site-deploy.yml"],
149
170
  cwd=root,
150
171
  text=True,
151
172
  stdout=subprocess.PIPE,
@@ -153,7 +174,7 @@ def validate(root: Path = ROOT) -> list[str]:
153
174
  check=False,
154
175
  )
155
176
  if pinned_workflow.returncode != 0:
156
- errors.append("consumer integration core SHA does not contain the reusable deploy workflow")
177
+ errors.append("consumer integration workflow SHA does not contain the reusable deploy workflow")
157
178
  else:
158
179
  try:
159
180
  pinned_deploy = load_workflow_text(pinned_workflow.stdout)
@@ -164,6 +185,14 @@ def validate(root: Path = ROOT) -> list[str]:
164
185
  f"consumer integration workflow: {error}"
165
186
  for error in reusable_deploy_input_errors(pinned_deploy)
166
187
  )
188
+ if "deployment_contract" in contract and contract["components"]["mcp"]["release_status"] == "ready":
189
+ recorded = subprocess.run(["git", "show", f"{workflow_sha}:src/unaltraweb_mcp/component-contract.json"],
190
+ cwd=root, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
191
+ try:
192
+ provider_contract = json.loads(recorded.stdout) if recorded.returncode == 0 else {}
193
+ errors.extend(selected_deployment_errors(contract, pinned_deploy, provider_contract))
194
+ except (ValueError, KeyError, TypeError):
195
+ errors.append("selected deployment workflow has no valid provider-owned component contract")
167
196
  if schema.get("properties", {}).get("schema_version", {}).get("const") != 1:
168
197
  errors.append("component contract schema does not select version 1")
169
198
 
@@ -273,7 +302,7 @@ def validate(root: Path = ROOT) -> list[str]:
273
302
  "Makefile.tmpl": ["__MCP_IMAGE__", "__MANUAL_PDF_IMAGE__"],
274
303
  ".github/workflows/deploy.yml.tmpl": [
275
304
  "__SITE_DEPLOY_WORKFLOW__",
276
- "__CORE_SHA__",
305
+ "__SITE_DEPLOY_WORKFLOW_SHA__",
277
306
  "__MANUAL_PDF_IMAGE__",
278
307
  "__VEGAVISUALS_SHA__",
279
308
  ],
@@ -52,6 +52,9 @@ PYPI_PUBLISH_IMAGE = (
52
52
  )
53
53
  # Canonical JSON digest of the complete unprivileged verification job.
54
54
  PACKAGE_PUBLISH_VERIFY_POLICY_SHA256 = "e8d99c35040770a2b00d3c62497da637739e794310b253d1893078d048d51c48"
55
+ # Canonical JSON of the complete provider-owned PDF digest/producer gate.
56
+ # Extending its reviewed release records also requires published-worker tests.
57
+ DEPLOY_PDF_PROVENANCE_POLICY_SHA256 = "da18b92db4069655e9979308dd90279ea8bfce4b77e47158efd5ac4421e06417"
55
58
  IMAGE_WORKFLOWS = {
56
59
  "compute-images.yml",
57
60
  "docker-image.yml",
@@ -119,14 +122,17 @@ def load_consumer_integration(root: Path) -> dict[str, Any]:
119
122
  "manual_pdf_image",
120
123
  "vegavisuals_sha",
121
124
  }
122
- if not isinstance(integration, dict) or set(integration) != required:
125
+ if not isinstance(integration, dict) or not required <= set(integration) or set(integration) - required - {"site_deploy_workflow_sha"}:
123
126
  raise ValueError("component contract has no exact consumer_integration object")
127
+ integration = dict(integration)
128
+ integration.setdefault("site_deploy_workflow_sha", integration["core_sha"])
124
129
  return integration
125
130
 
126
131
 
127
132
  def load_scaffold_deploy(path: Path, integration: dict[str, Any]) -> dict[str, Any]:
128
133
  replacements = {
129
134
  "CORE_SHA": str(integration["core_sha"]),
135
+ "SITE_DEPLOY_WORKFLOW_SHA": str(integration["site_deploy_workflow_sha"]),
130
136
  "SITE_DEPLOY_WORKFLOW": str(integration["site_deploy_workflow"]),
131
137
  "MANUAL_PDF_IMAGE": str(integration["manual_pdf_image"]),
132
138
  "VEGAVISUALS_SHA": str(integration["vegavisuals_sha"]),
@@ -213,6 +219,7 @@ def validate_workflows(root: Path = WORKFLOW_ROOT) -> list[str]:
213
219
  integration = {
214
220
  "core_sha": "invalid",
215
221
  "site_deploy_workflow": "invalid",
222
+ "site_deploy_workflow_sha": "invalid",
216
223
  "manual_pdf_image": "invalid",
217
224
  "vegavisuals_sha": "invalid",
218
225
  }
@@ -1047,6 +1054,16 @@ def validate_workflows(root: Path = WORKFLOW_ROOT) -> list[str]:
1047
1054
  if marker not in ci_text:
1048
1055
  errors.append(f"ci.yml: missing required check {marker}")
1049
1056
  ci_docker = ci.get("jobs", {}).get("docker", {})
1057
+ published_pdf_gate = _named_step(ci.get("jobs", {}).get("distribution", {}), "Test published PDF deployment provenance")
1058
+ if published_pdf_gate != {
1059
+ "name": "Test published PDF deployment provenance",
1060
+ "env": {
1061
+ "UNALTRAWEB_DEPLOY_PROVENANCE_DOCKER": "1",
1062
+ "UNALTRAWEB_DEPLOY_PROVENANCE_SOURCE_SHA": "${{ github.event.pull_request.head.sha || github.sha }}",
1063
+ },
1064
+ "run": "PYTHONPATH=test python -m unittest test_deploy_provenance.PublishedDeployProvenanceTests",
1065
+ }:
1066
+ errors.append("ci.yml: published PDF deployment provenance must run unconditionally with real Docker")
1050
1067
  ruby_tests = str(_named_step(ci_docker, "Test all Ruby files").get("run") or "")
1051
1068
  if not all(
1052
1069
  marker in ruby_tests
@@ -1362,8 +1379,20 @@ def validate_workflows(root: Path = WORKFLOW_ROOT) -> list[str]:
1362
1379
  for marker in ["MANUAL_PDF_IMAGE", "WORKFLOW_REPOSITORY", "WORKFLOW_SHA", "docker pull", "docker image inspect", "org.opencontainers.image.revision"]:
1363
1380
  if marker not in provenance_text:
1364
1381
  errors.append(f"site-deploy.yml: PDF worker provenance check missing {marker}")
1365
- if '[[ "$image_revision" != "$WORKFLOW_SHA" ]]' not in provenance_text:
1366
- errors.append("site-deploy.yml: PDF worker revision label must be compared with the defining workflow SHA")
1382
+ if '[[ "$image_revision" != "$expected_pdf_revision" ]]' not in provenance_text:
1383
+ errors.append("site-deploy.yml: PDF worker revision label must be compared with its recorded producer SHA")
1384
+ provenance_sha256 = hashlib.sha256(
1385
+ json.dumps(provenance_step, sort_keys=True, separators=(",", ":")).encode()
1386
+ ).hexdigest()
1387
+ if provenance_sha256 != DEPLOY_PDF_PROVENANCE_POLICY_SHA256:
1388
+ errors.append("site-deploy.yml: PDF digest/producer gate differs from the exact reviewed structure")
1389
+ try:
1390
+ contract = json.loads((ROOT / "src/unaltraweb_mcp/component-contract.json").read_text())
1391
+ records = contract["deployment_contract"]["manual_pdf_workers"]
1392
+ if sum(row.get("reference") == integration["manual_pdf_image"] for row in records) != 1:
1393
+ errors.append("site-deploy.yml: selected PDF worker has no reviewed digest/producer record")
1394
+ except (OSError, ValueError, KeyError, TypeError):
1395
+ errors.append("site-deploy.yml: missing or invalid provider deployment records")
1367
1396
  if "docker pull" in provenance_text and "docker image inspect" in provenance_text and provenance_text.index("docker pull") > provenance_text.index("docker image inspect"):
1368
1397
  errors.append("site-deploy.yml: PDF worker digest must be pulled before its revision label is inspected")
1369
1398
  if "${{ github.workflow_sha }}" in deploy_text or "${{ github.workflow_repository }}" in deploy_text:
@@ -1542,7 +1571,7 @@ def validate_workflows(root: Path = WORKFLOW_ROOT) -> list[str]:
1542
1571
  action, separator, revision = uses.rpartition("@")
1543
1572
  if not separator or action != integration["site_deploy_workflow"] or not FULL_SHA.fullmatch(revision):
1544
1573
  errors.append(f"scaffold deploy.yml:{job_name}: reusable workflow must use an immutable unaltraweb SHA")
1545
- elif revision != integration["core_sha"]:
1574
+ elif revision != integration["site_deploy_workflow_sha"]:
1546
1575
  errors.append(f"scaffold deploy.yml:{job_name}: reusable workflow SHA has not been reviewed")
1547
1576
  reusable_job = scaffold.get("jobs", {}).get(job_name, {})
1548
1577
  if reusable_job.get("needs") != "validate":
@@ -2,17 +2,43 @@
2
2
  "$schema": "component-contract.schema.json",
3
3
  "schema_version": 1,
4
4
  "release": {
5
- "version": "0.7.0",
6
- "tag": "v0.7.0"
5
+ "version": "0.7.1",
6
+ "tag": "v0.7.1"
7
7
  },
8
8
  "consumer_integration": {
9
9
  "schema_version": 1,
10
10
  "core_repository": "https://github.com/dosquartsdedocs/unaltraweb.git",
11
- "core_sha": "216ab2e8b6b8b45a5bb7da0a54bffd10edee895d",
11
+ "core_sha": "3332e0b93933f12317e05f1ce8d38ce80046feab",
12
12
  "site_deploy_workflow": "dosquartsdedocs/unaltraweb/.github/workflows/site-deploy.yml",
13
- "manual_pdf_image": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed",
13
+ "site_deploy_workflow_sha": "3332e0b93933f12317e05f1ce8d38ce80046feab",
14
+ "manual_pdf_image": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:1bb3f2dafd741e96c28639ec1cc8ccaeb81cbaa73e649f787c0b4ef59997bd4b",
14
15
  "vegavisuals_sha": "a448cc50a5f511743a6fcfc213baeb9be80f4a27"
15
16
  },
17
+ "deployment_contract": {
18
+ "schema_version": 1,
19
+ "manual_pdf_workers": [
20
+ {
21
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:9e0b3a45753c170b795e9a9d6df61580085c113436beac5bf6c8de69b6562097",
22
+ "producer_sha": "d857f8c9f5fea90cf450c0b30b4e77a37b541275"
23
+ },
24
+ {
25
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed",
26
+ "producer_sha": "5cf9817489c8dc47cee726bfe42fe3071cd32b85"
27
+ },
28
+ {
29
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:1bb3f2dafd741e96c28639ec1cc8ccaeb81cbaa73e649f787c0b4ef59997bd4b",
30
+ "producer_sha": "b7ec1d7a139c65b3b0b88699cdbeb19080f13be1"
31
+ }
32
+ ],
33
+ "caller_migrations": [
34
+ {
35
+ "id": "deploy-provenance-86",
36
+ "path": ".github/workflows/deploy.yml",
37
+ "baseline_sha256": "a789870542614d5817d30ea4328c7d1ad38d27443c009c68a48ad5aaa3106b8e",
38
+ "current_sha256": "c632a548d0782867be20a2a52fe03469cf63066b7364bace77fd54a226cb3b18"
39
+ }
40
+ ]
41
+ },
16
42
  "receipt_contract": {
17
43
  "schema_version": 1,
18
44
  "path_template": ".unaltraweb/receipts/{provider}.json",
@@ -36,10 +62,10 @@
36
62
  "gem": {
37
63
  "kind": "gem",
38
64
  "name": "unaltraweb",
39
- "version": "0.7.0",
40
- "release": "v0.7.0",
65
+ "version": "0.7.1",
66
+ "release": "v0.7.1",
41
67
  "release_status": "ready",
42
- "reference": "unaltraweb (= 0.7.0)",
68
+ "reference": "unaltraweb (= 0.7.1)",
43
69
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
44
70
  "included_in_wheel": false,
45
71
  "features": ["jekyll-core", "site-build"]
@@ -47,10 +73,10 @@
47
73
  "wheel": {
48
74
  "kind": "python-wheel",
49
75
  "name": "unaltraweb-mcp",
50
- "version": "0.7.0",
51
- "release": "v0.7.0",
76
+ "version": "0.7.1",
77
+ "release": "v0.7.1",
52
78
  "release_status": "ready",
53
- "reference": "unaltraweb-mcp==0.7.0",
79
+ "reference": "unaltraweb-mcp==0.7.1",
54
80
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
55
81
  "included_in_wheel": true,
56
82
  "features": ["calibre-import", "doctor", "new-web", "offline-inspection", "mcp-control-plane"]
@@ -58,10 +84,10 @@
58
84
  "runtime": {
59
85
  "kind": "container",
60
86
  "name": "unaltraweb runtime",
61
- "version": "0.7.0",
62
- "release": "v0.7.0",
87
+ "version": "0.7.1",
88
+ "release": "v0.7.1",
63
89
  "release_status": "ready",
64
- "reference": "ghcr.io/dosquartsdedocs/unaltraweb:0.7.0",
90
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb:0.7.1",
65
91
  "image_repository": "ghcr.io/dosquartsdedocs/unaltraweb",
66
92
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
67
93
  "included_in_wheel": false,
@@ -70,10 +96,10 @@
70
96
  "mcp": {
71
97
  "kind": "container",
72
98
  "name": "unaltraweb MCP runtime",
73
- "version": "0.7.0",
74
- "release": "v0.7.0",
99
+ "version": "0.7.1",
100
+ "release": "v0.7.1",
75
101
  "release_status": "ready",
76
- "reference": "ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.0",
102
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.1",
77
103
  "image_repository": "ghcr.io/dosquartsdedocs/unaltraweb-mcp",
78
104
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
79
105
  "included_in_wheel": false,
@@ -118,10 +144,10 @@
118
144
  "manual_pdf": {
119
145
  "kind": "container",
120
146
  "name": "unaltraweb manual PDF worker",
121
- "version": "0.6.0",
122
- "release": "v0.6.0",
147
+ "version": "0.7.1",
148
+ "release": "v0.7.1",
123
149
  "release_status": "released",
124
- "reference": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed",
150
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:1bb3f2dafd741e96c28639ec1cc8ccaeb81cbaa73e649f787c0b4ef59997bd4b",
125
151
  "image_repository": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf",
126
152
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
127
153
  "included_in_wheel": false,
@@ -7,7 +7,7 @@
7
7
  "required": ["schema_version", "release", "consumer_integration", "receipt_contract", "wheel_contract", "components"],
8
8
  "properties": {
9
9
  "$schema": {"type": "string"},
10
- "schema_version": {"const": 1},
10
+ "schema_version": {"type": "integer", "const": 1},
11
11
  "release": {
12
12
  "type": "object",
13
13
  "additionalProperties": false,
@@ -22,14 +22,47 @@
22
22
  "additionalProperties": false,
23
23
  "required": ["schema_version", "core_repository", "core_sha", "site_deploy_workflow", "manual_pdf_image", "vegavisuals_sha"],
24
24
  "properties": {
25
- "schema_version": {"const": 1},
25
+ "schema_version": {"type": "integer", "const": 1},
26
26
  "core_repository": {"const": "https://github.com/dosquartsdedocs/unaltraweb.git"},
27
27
  "core_sha": {"type": "string", "minLength": 40, "maxLength": 40, "pattern": "^[0-9a-f]{40}$"},
28
28
  "site_deploy_workflow": {"const": "dosquartsdedocs/unaltraweb/.github/workflows/site-deploy.yml"},
29
+ "site_deploy_workflow_sha": {"type": "string", "minLength": 40, "maxLength": 40, "pattern": "^[0-9a-f]{40}$"},
29
30
  "manual_pdf_image": {"type": "string", "minLength": 117, "maxLength": 117, "pattern": "^ghcr\\.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:[0-9a-f]{64}$"},
30
31
  "vegavisuals_sha": {"type": "string", "minLength": 40, "maxLength": 40, "pattern": "^[0-9a-f]{40}$"}
31
32
  }
32
33
  },
34
+ "deployment_contract": {
35
+ "type": "object",
36
+ "additionalProperties": false,
37
+ "required": ["schema_version", "manual_pdf_workers", "caller_migrations"],
38
+ "properties": {
39
+ "schema_version": {"type": "integer", "const": 1},
40
+ "manual_pdf_workers": {
41
+ "type": "array", "minItems": 1, "uniqueItems": true,
42
+ "items": {
43
+ "type": "object", "additionalProperties": false,
44
+ "required": ["reference", "producer_sha"],
45
+ "properties": {
46
+ "reference": {"type": "string", "minLength": 117, "maxLength": 117, "pattern": "^ghcr\\.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:[0-9a-f]{64}$"},
47
+ "producer_sha": {"type": "string", "minLength": 40, "maxLength": 40, "pattern": "^[0-9a-f]{40}$"}
48
+ }
49
+ }
50
+ },
51
+ "caller_migrations": {
52
+ "type": "array", "uniqueItems": true,
53
+ "items": {
54
+ "type": "object", "additionalProperties": false,
55
+ "required": ["id", "path", "baseline_sha256", "current_sha256"],
56
+ "properties": {
57
+ "id": {"type": "string", "pattern": "^[a-z][a-z0-9-]{0,63}$"},
58
+ "path": {"const": ".github/workflows/deploy.yml"},
59
+ "baseline_sha256": {"type": "string", "minLength": 64, "maxLength": 64, "pattern": "^[0-9a-f]{64}$"},
60
+ "current_sha256": {"type": "string", "minLength": 64, "maxLength": 64, "pattern": "^[0-9a-f]{64}$"}
61
+ }
62
+ }
63
+ }
64
+ }
65
+ },
33
66
  "receipt_contract": {
34
67
  "type": "object",
35
68
  "additionalProperties": false,
@@ -20,7 +20,15 @@ def _strict_json(path: Path) -> Any:
20
20
  def reject(value: str) -> None:
21
21
  raise ValueError(f"non-finite JSON number is not allowed: {value}")
22
22
 
23
- return json.loads(path.read_text(encoding="utf-8"), parse_constant=reject)
23
+ def unique(pairs):
24
+ result = {}
25
+ for key, value in pairs:
26
+ if key in result:
27
+ raise ValueError(f"duplicate component contract key: {key}")
28
+ result[key] = value
29
+ return result
30
+
31
+ return json.loads(path.read_text(encoding="utf-8"), parse_constant=reject, object_pairs_hook=unique)
24
32
 
25
33
 
26
34
  def _schema_type_matches(value: Any, expected: str) -> bool:
@@ -155,6 +163,9 @@ def component_contract_semantic_errors(value: dict[str, Any]) -> list[str]:
155
163
  expected_workflow = f"{expected_core_repository.removeprefix('https://github.com/').removesuffix('.git')}/.github/workflows/site-deploy.yml"
156
164
  if integration["site_deploy_workflow"] != expected_workflow:
157
165
  errors.append("consumer integration deploy workflow must belong to the core provider")
166
+ workflow_sha = str(integration.get("site_deploy_workflow_sha", core_sha))
167
+ if re.fullmatch(r"[0-9a-f]{40}", workflow_sha) is None or workflow_sha == "0" * 40:
168
+ errors.append("consumer integration workflow SHA must be a nonzero full lowercase commit SHA")
158
169
  expected_pdf_prefix = f"{value['components']['manual_pdf']['image_repository']}@sha256:"
159
170
  manual_pdf_image = str(integration["manual_pdf_image"])
160
171
  if re.fullmatch(rf"{re.escape(expected_pdf_prefix)}[0-9a-f]{{64}}", manual_pdf_image) is None or manual_pdf_image.endswith("0" * 64):
@@ -162,6 +173,26 @@ def component_contract_semantic_errors(value: dict[str, Any]) -> list[str]:
162
173
  vegavisuals_sha = str(integration["vegavisuals_sha"])
163
174
  if re.fullmatch(r"[0-9a-f]{40}", vegavisuals_sha) is None or vegavisuals_sha == "0" * 40:
164
175
  errors.append("consumer integration Vega revision must be a nonzero full lowercase commit SHA")
176
+ deployment = value.get("deployment_contract")
177
+ if deployment is not None:
178
+ references = [row["reference"] for row in deployment["manual_pdf_workers"]]
179
+ if not 1 <= len(references) <= 64:
180
+ errors.append("deployment worker inventory must contain between 1 and 64 records")
181
+ if len(set(references)) != len(references):
182
+ errors.append("deployment worker references must be unique")
183
+ if manual_pdf_image not in references or value["components"]["manual_pdf"]["reference"] != manual_pdf_image:
184
+ errors.append("selected PDF worker must match a reviewed deployment record and the component reference")
185
+ for row in deployment["manual_pdf_workers"]:
186
+ if row["producer_sha"] == "0" * 40 or row["reference"].endswith("0" * 64):
187
+ errors.append("deployment worker identities must be nonzero")
188
+ migrations = deployment["caller_migrations"]
189
+ if len(migrations) > 32:
190
+ errors.append("deployment caller migration inventory exceeds 32 records")
191
+ if len({row["id"] for row in migrations}) != len(migrations) or len({(row["path"], row["baseline_sha256"], row["current_sha256"]) for row in migrations}) != len(migrations):
192
+ errors.append("deployment caller migrations must be unique")
193
+ for row in migrations:
194
+ if row["baseline_sha256"] == row["current_sha256"] or "0" * 64 in (row["baseline_sha256"], row["current_sha256"]):
195
+ errors.append("deployment caller migration requires distinct nonzero baseline and current hashes")
165
196
  return errors
166
197
 
167
198
 
@@ -194,7 +225,16 @@ def distribution_version() -> str:
194
225
 
195
226
  def consumer_integration() -> dict[str, Any]:
196
227
  """Return an isolated copy of the reviewed consumer runtime tuple."""
197
- return dict(_contract()["consumer_integration"])
228
+ result = dict(_contract()["consumer_integration"])
229
+ result.setdefault("site_deploy_workflow_sha", result["core_sha"])
230
+ return result
231
+
232
+
233
+ def deployment_contract() -> dict[str, Any]:
234
+ """Provider-owned identities and exact reviewed caller migrations."""
235
+ return json.loads(json.dumps(_contract().get("deployment_contract", {
236
+ "schema_version": 1, "manual_pdf_workers": [], "caller_migrations": [],
237
+ })))
198
238
 
199
239
 
200
240
  def component(component_id: str) -> dict[str, Any]:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unaltraweb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - dosquartsdedocs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-05 00:00:00.000000000 Z
11
+ date: 2026-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: classifier-reborn
@@ -801,10 +801,13 @@ files:
801
801
  - docs/agents/action-prompts/60-bibliometrics-refresh.txt
802
802
  - docs/agents/action-prompts/70-build-and-review.txt
803
803
  - docs/agents/d0-runtime-identity.md
804
+ - docs/agents/deploy-provenance-86.md
805
+ - docs/agents/deployment-integration-0.7.1.md
804
806
  - docs/agents/manual-authoring-components.md
805
807
  - docs/agents/mcp-contract.md
806
808
  - docs/agents/owner-closeout-76.md
807
809
  - docs/agents/owner-closeout-80.md
810
+ - docs/agents/owner-closeout-85.md
808
811
  - docs/agents/owner-followup-76.md
809
812
  - docs/agents/owner-preparation-2026-09-29.md
810
813
  - docs/agents/quarto-computation-adoption.md