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 +4 -4
- data/Makefile +5 -5
- data/docs/_documentation/en/33-reusable-workflows.md +28 -3
- data/docs/_documentation/en/40-distribution.md +33 -18
- data/docs/_documentation/en/46-live-runtime.md +6 -3
- data/docs/agents/d0-runtime-identity.md +14 -5
- data/docs/agents/deploy-provenance-86.md +86 -0
- data/docs/agents/deployment-integration-0.7.1.md +138 -0
- data/docs/agents/mcp-contract.md +5 -4
- data/docs/agents/owner-closeout-85.md +269 -0
- data/scripts/test_wheel_install.py +1 -1
- data/scripts/unaltraweb-mcp-bootstrap.sh +1 -1
- data/scripts/validate_distribution.py +33 -4
- data/scripts/validate_workflows.py +33 -4
- data/src/unaltraweb_mcp/component-contract.json +45 -19
- data/src/unaltraweb_mcp/component-contract.schema.json +35 -2
- data/src/unaltraweb_mcp/distribution.py +42 -2
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5697f730a670b00edc9d6cda6bb653552470c6c58667d27557e33309203f552c
|
|
4
|
+
data.tar.gz: 1fb32fa043262eca9724aed6dc0184246bc6012f2a6261037f03203ef1265945
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
5
|
-
MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.
|
|
6
|
-
MCP_RELEASE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:
|
|
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.
|
|
44
|
-
MANUAL_PDF_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:
|
|
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
|
-
|
|
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
|
|
28
|
+
### Published 0.7.0 release
|
|
29
29
|
|
|
30
|
-
|
|
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
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
128
|
+
### 0.7.0 component selection
|
|
114
129
|
|
|
115
|
-
The coordinated core identity is **0.
|
|
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
|
|
119
|
-
|
|
120
|
-
still require the coordinated version.
|
|
121
|
-
unchanged. Signed image/package evidence is recorded in the 0.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
87
|
-
|
|
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
|
-
|
|
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
|
|
122
|
-
[Diavisuals 14](https://github.com/dosquartsdedocs/diavisuals/issues/14)
|
|
123
|
-
|
|
124
|
-
|
|
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.
|
data/docs/agents/mcp-contract.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# MCP Contract
|
|
2
2
|
|
|
3
|
-
The D0 additions
|
|
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.
|
|
41
|
-
`sha256:
|
|
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["
|
|
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:
|
|
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"{
|
|
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
|
|
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
|
-
"
|
|
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)
|
|
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" != "$
|
|
1366
|
-
errors.append("site-deploy.yml: PDF worker revision label must be compared with
|
|
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["
|
|
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.
|
|
6
|
-
"tag": "v0.7.
|
|
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": "
|
|
11
|
+
"core_sha": "3332e0b93933f12317e05f1ce8d38ce80046feab",
|
|
12
12
|
"site_deploy_workflow": "dosquartsdedocs/unaltraweb/.github/workflows/site-deploy.yml",
|
|
13
|
-
"
|
|
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.
|
|
40
|
-
"release": "v0.7.
|
|
65
|
+
"version": "0.7.1",
|
|
66
|
+
"release": "v0.7.1",
|
|
41
67
|
"release_status": "ready",
|
|
42
|
-
"reference": "unaltraweb (= 0.7.
|
|
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.
|
|
51
|
-
"release": "v0.7.
|
|
76
|
+
"version": "0.7.1",
|
|
77
|
+
"release": "v0.7.1",
|
|
52
78
|
"release_status": "ready",
|
|
53
|
-
"reference": "unaltraweb-mcp==0.7.
|
|
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.
|
|
62
|
-
"release": "v0.7.
|
|
87
|
+
"version": "0.7.1",
|
|
88
|
+
"release": "v0.7.1",
|
|
63
89
|
"release_status": "ready",
|
|
64
|
-
"reference": "ghcr.io/dosquartsdedocs/unaltraweb:0.7.
|
|
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.
|
|
74
|
-
"release": "v0.7.
|
|
99
|
+
"version": "0.7.1",
|
|
100
|
+
"release": "v0.7.1",
|
|
75
101
|
"release_status": "ready",
|
|
76
|
-
"reference": "ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.
|
|
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.
|
|
122
|
-
"release": "v0.
|
|
147
|
+
"version": "0.7.1",
|
|
148
|
+
"release": "v0.7.1",
|
|
123
149
|
"release_status": "released",
|
|
124
|
-
"reference": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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-
|
|
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
|