unaltraweb 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Makefile +13 -11
- data/_plugins/retained_documents.rb +62 -0
- data/docs/_documentation/en/40-distribution.md +73 -19
- data/docs/_documentation/en/45-retained-documents.md +138 -0
- data/docs/_documentation/en/46-live-runtime.md +89 -0
- data/docs/agents/d0-runtime-identity.md +200 -0
- data/docs/agents/mcp-contract.md +45 -2
- data/docs/agents/owner-closeout-76.md +205 -0
- data/docs/agents/owner-closeout-80.md +185 -0
- data/docs/agents/retained-letter-import.md +235 -0
- data/lib/unaltraweb.rb +1 -0
- data/requirements.txt +2 -0
- data/scripts/manual/Dockerfile +7 -4
- data/scripts/manual/build_pdf.py +28 -0
- data/scripts/manual/templates/manual.tex +1 -0
- data/scripts/test_gem_build.py +27 -0
- data/scripts/test_wheel_install.py +7 -2
- data/scripts/unaltraweb-mcp-bootstrap.sh +90 -9
- data/scripts/unaltraweb-mcp-cleanup.sh +41 -9
- data/scripts/web_captures/render.py +8 -1
- data/src/unaltraweb_mcp/__init__.py +4 -0
- data/src/unaltraweb_mcp/artifact-handoff-v1.schema.json +102 -0
- data/src/unaltraweb_mcp/artifact_handoff_v1.py +435 -0
- data/src/unaltraweb_mcp/artifact_imports.py +368 -0
- data/src/unaltraweb_mcp/component-contract.json +27 -27
- data/src/unaltraweb_mcp/distribution.py +887 -0
- data/src/unaltraweb_mcp/letter_bundle.py +223 -0
- data/src/unaltraweb_mcp/pdf_probe.py +63 -0
- metadata +16 -2
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# unaltraweb 0.6.0 delivery closeout
|
|
2
|
+
|
|
3
|
+
Published **2026-10-02 17:28:14 UTC**:
|
|
4
|
+
[v0.6.0](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.6.0).
|
|
5
|
+
Owner coordination: [issue 80](https://github.com/dosquartsdedocs/unaltraweb/issues/80).
|
|
6
|
+
This report supersedes the pending delivery state in the chronological
|
|
7
|
+
[preparation record](retained-letter-import.md). Issue 76 and release 0.5.1
|
|
8
|
+
remain closed and immutable.
|
|
9
|
+
|
|
10
|
+
## Review, source and integration
|
|
11
|
+
|
|
12
|
+
The owner explicitly authorized commits, push, PR review/integration, signed
|
|
13
|
+
candidate workflows, gated publication and the post-release launcher pin. The
|
|
14
|
+
checkout was reconciled against all existing unit-80 paths; no unrelated edits
|
|
15
|
+
were found. Work used one checkout and ordinary serial branches.
|
|
16
|
+
|
|
17
|
+
| Role | Revision / evidence |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| Reviewed implementation | `7af652fb83629e959af05c407a34a2f5a15f7936` |
|
|
20
|
+
| Integrated core selected by consumers | `5cf9817489c8dc47cee726bfe42fe3071cd32b85`, [PR 81](https://github.com/dosquartsdedocs/unaltraweb/pull/81) |
|
|
21
|
+
| Immutable core/PDF selection | `8e93b8b808204faef54cccaee622699f04a11805` |
|
|
22
|
+
| Final artifact-producing source | `de52db351490e94939aac20c6af264f22a6a1678`, [PR 82](https://github.com/dosquartsdedocs/unaltraweb/pull/82) |
|
|
23
|
+
| Receipt-only child | `3ce7606bc6148aee19d067c559823d8c5b52db5d` |
|
|
24
|
+
| Receipt integration and tag target | `ec6dcb28e890d32718aa173934527a7b4213a042`, [PR 83](https://github.com/dosquartsdedocs/unaltraweb/pull/83) |
|
|
25
|
+
| Annotated tag object | `1605578861a1a09157037e6085020baad4948d72` |
|
|
26
|
+
|
|
27
|
+
All three PRs have explicit agent review records and protected CI; those records
|
|
28
|
+
do not claim human review. Merge commits preserve the reviewed core's ancestry.
|
|
29
|
+
The receipt integration's first parent is exactly the artifact-producing source,
|
|
30
|
+
and its first-parent diff contains only `release-candidates.json`.
|
|
31
|
+
|
|
32
|
+
Review closed independent metadata-reference validation, malformed Pandoc-link
|
|
33
|
+
handling, internal PDF OpenAction destinations, and direct signed-runtime
|
|
34
|
+
acceptance. The vendored v1 verifier/schema still match the established hub pin
|
|
35
|
+
byte for byte; 26 reference conformance tests passed against matching fixtures.
|
|
36
|
+
Source checks reported 587 Python cases with 30 optional skips. Ruby, actual PDF,
|
|
37
|
+
MCP, wheel/gem, workflow/distribution, docs and reproducibility gates passed.
|
|
38
|
+
|
|
39
|
+
## Receipt and published identities
|
|
40
|
+
|
|
41
|
+
[Tagged native receipt](https://github.com/dosquartsdedocs/unaltraweb/blob/v0.6.0/release-candidates.json):
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
schema_version: 1
|
|
45
|
+
release: v0.6.0
|
|
46
|
+
source_commit: de52db351490e94939aac20c6af264f22a6a1678
|
|
47
|
+
receipt SHA-256: 5ed4e6dd615367927e6ea8a3541c9e7dca9dad73a738851705f563e0e6895280
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Exactly the four `ready` components are bound to that source:
|
|
51
|
+
|
|
52
|
+
| Component | Registry artifact | SHA-256 / OCI index digest |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| Gem | `unaltraweb-0.6.0.gem` | `276d04a71d1170220c3881cce8d0800633c42b0ee7ad07a376f80996c6afd177` |
|
|
55
|
+
| Wheel | `unaltraweb_mcp-0.6.0-py3-none-any.whl` | `3effb471ffd264f7fb2a8c88dd6536bc86639eae52806527c2d872653944c85a` |
|
|
56
|
+
| Base runtime | `ghcr.io/dosquartsdedocs/unaltraweb` | `sha256:a4e9d82b0e9a72e519c44e09ca449b2dc37964fbb9953ae6e4adff648e39b94b` |
|
|
57
|
+
| Full MCP | `ghcr.io/dosquartsdedocs/unaltraweb-mcp` | `sha256:736c4ddd0a543454e3edaeac2e9cfd97a1279ce472923ac54e326c1281b2ba05` |
|
|
58
|
+
|
|
59
|
+
Both `0.6.0` and `v0.6.0` OCI aliases were inspected anonymously and match those
|
|
60
|
+
index digests. The MCP's local configuration ID is
|
|
61
|
+
`sha256:73320210b19597243c7183ef255ffa1cbc36a07157e6ab4e1b3d9349fa89a063`;
|
|
62
|
+
its revision label is the exact artifact source above. Configuration IDs and
|
|
63
|
+
registry index digests are distinct identities.
|
|
64
|
+
|
|
65
|
+
The selected PDF 0.6.0 is the already-published, signed and tested specialization:
|
|
66
|
+
`ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed`.
|
|
67
|
+
It was produced from core `5cf9817489c8dc47cee726bfe42fe3071cd32b85` by the
|
|
68
|
+
[initial signed image run](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37029374441),
|
|
69
|
+
and its local configuration ID is
|
|
70
|
+
`sha256:d7e7d3243616270fc9e6eed7f8238c412dbe3d9ffc18d2832d17d66ca630d139`.
|
|
71
|
+
The BOM, generated consumer tuple and Make default select that same digest.
|
|
72
|
+
It is reused as `released`, outside the four-component coordinated receipt.
|
|
73
|
+
The later image workflow also tested a verification-only PDF candidate
|
|
74
|
+
`sha256:9b3ae6fe1f04ff7de6c81c258d7c16f79cc7f2857c9b46b0829fc71812ace11f`;
|
|
75
|
+
that candidate is not the selected worker and received no coordinated semver
|
|
76
|
+
promotion. No self-digest or fabricated core SHA was introduced.
|
|
77
|
+
|
|
78
|
+
Computation, capture, Diavisuals and Vegavisuals retain the tested 0.4.0 selections.
|
|
79
|
+
Their exact immutable references remain in the BOM, and earlier published
|
|
80
|
+
artifacts and receipts remain at their original tags.
|
|
81
|
+
|
|
82
|
+
## CI, signing and publication
|
|
83
|
+
|
|
84
|
+
| Gate | Successful run |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| Implementation PR CI / CodeQL | [37027921742](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37027921742) / [37027922332](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37027922332) |
|
|
87
|
+
| Core integration CI | [37028677932](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37028677932) |
|
|
88
|
+
| Tuple PR CI / CodeQL | [37032368507](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37032368507) / [37032368609](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37032368609) |
|
|
89
|
+
| Final source CI / CodeQL | [37033064607](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37033064607) / [37033064633](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37033064633) |
|
|
90
|
+
| Signed final image build/test | [37033593312](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37033593312) |
|
|
91
|
+
| Package preparation | [37033596931](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37033596931) |
|
|
92
|
+
| Receipt PR CI / CodeQL | [37038403708](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37038403708) / [37038403802](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37038403802) |
|
|
93
|
+
| Receipt/tag target CI / CodeQL | [37039075585](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37039075585) / [37039075748](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37039075748) |
|
|
94
|
+
| Tag CI | [37039786598](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37039786598) |
|
|
95
|
+
| Semver image promotion | [37040420721](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37040420721) |
|
|
96
|
+
| PyPI/RubyGems Trusted Publishing | [37040424945](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37040424945) |
|
|
97
|
+
|
|
98
|
+
The signed image workflows checked exact OCI digests, signer workflow, source
|
|
99
|
+
revision and labels before executing candidates. Promotion reverified those
|
|
100
|
+
bindings and reused the tested manifests without rebuilding. The package
|
|
101
|
+
authorizer bound workflow/run/source, immutable artifact ID `11237594327`, exact
|
|
102
|
+
inventory and checksums to the receipt. Its archive digest is
|
|
103
|
+
`sha256:79a67d7a8370468abe1f0265b248f3e9d6cf6187ac0bc891a0b3801e5a9931a6`.
|
|
104
|
+
OIDC jobs published only the staged verified gem and wheel.
|
|
105
|
+
|
|
106
|
+
The actual receipt-only branch, merged target and annotated tag passed strict
|
|
107
|
+
`distribution-release-check` and publication-ref/ancestry gates. Native package
|
|
108
|
+
run authorization, exact staging and `verify_package_publish.py release` passed
|
|
109
|
+
before privileged publication. Strict release checks apply to the receipt/tag
|
|
110
|
+
revision, not subsequent ordinary post-release source commits.
|
|
111
|
+
|
|
112
|
+
## Real retained-letter and rollback proofs
|
|
113
|
+
|
|
114
|
+
Acceptance consumed the authenticated published Carta 0.3.0rc1 packet, not a local
|
|
115
|
+
producer checkout or synthetic unit fixture. The sender bundle hash is
|
|
116
|
+
`aeaa757ee1be19bfe56dc9af8dd1178032929b4a2bec2dad2ebb621b158ad999`.
|
|
117
|
+
All 12 seal files remain under `.unaltraweb/artifacts/carta/bundle/`.
|
|
118
|
+
The mapping `payload/output/letter.pdf` → `assets/documents/carta.pdf` retains
|
|
119
|
+
SHA-256 `4a661740a18fe1cf75b84aa0d8532511fd105eb5484a5af700e11e8e30828ea4`.
|
|
120
|
+
The native chapter is `_chapters/en/carta.md`, with its separate binding and
|
|
121
|
+
standard-v1 integration record outside the seal.
|
|
122
|
+
|
|
123
|
+
The downloaded final CI wheel ran against the exact signed MCP and selected PDF
|
|
124
|
+
digests above, without deriving another controller image. Both copied producer
|
|
125
|
+
and incoming trees were removed, author prose survived an identical reimport,
|
|
126
|
+
and the receiver was moved before native/generic verification and a forced PDF
|
|
127
|
+
rebuild. Web/HTTP checks passed at both locations. The complete original letter
|
|
128
|
+
appears on page 10 of an 11-page composed manual. Both composed PDFs have hash
|
|
129
|
+
`416e96f66bb6608b1e20bf5e36b6b16133bd4018c17e6c079e8987b736fe9cae`.
|
|
130
|
+
The integration record hash is
|
|
131
|
+
`ebe07ee10ad740a2bbbd36d532f336374cf4bb19ccb373b6590b2279f664a222`.
|
|
132
|
+
Generic verification confirms one bundle, one mapping and 14 verified files;
|
|
133
|
+
the native checker additionally binds the source and rendered page.
|
|
134
|
+
|
|
135
|
+
Local evidence root: `/tmp/opencode/unaltraweb-closeout-060/`.
|
|
136
|
+
|
|
137
|
+
| Retained evidence | SHA-256 |
|
|
138
|
+
| --- | --- |
|
|
139
|
+
| `candidate-letter-proof/evidence.json` | `618573b1a867daf6b1f3023e0d5700c27a6de429abea160b4c51ff8699f86f9c` |
|
|
140
|
+
| `candidate-roundtrip/evidence.json` | `23ec8885e8306931fb8ee4899e95b7bff4b3d23d2b63cdd3321e3f68722c3bb8` |
|
|
141
|
+
| `published-packages/verified.json` | `073d7ca1bbe46b8be5d89211501ca8fc7b71297d7eb542c4c9cc27ff167aa91e` |
|
|
142
|
+
|
|
143
|
+
The roundtrip exercised all four profiles using immutable MCP references:
|
|
144
|
+
0.4.0 `sha256:389bc585cdb4fc89d3372f4896a55fe26e15df38b46bc114ce44fdb3f1c8deb9`,
|
|
145
|
+
unpatched 0.5.0 `sha256:36d17edbade77edb40a687f6a744203c6329acb33fbc2eb255e88d9ff1a42c98`,
|
|
146
|
+
then the new 0.6.0 digest. The unpatched failure was reproduced on a separate
|
|
147
|
+
copy. Two builds and a preview passed at 0.6.0 and again after returning to 0.4.0.
|
|
148
|
+
All six author/cache files retained their hashes; no caches were emptied.
|
|
149
|
+
|
|
150
|
+
## Public downloads and post-release selection
|
|
151
|
+
|
|
152
|
+
Anonymous PyPI and RubyGems metadata and package bytes match the receipt exactly.
|
|
153
|
+
GitHub Release assets were downloaded again and pass `SHA256SUMS`, whose own hash
|
|
154
|
+
is `60d80d6e0803154a7b5c98c1731f4bec905def3a481152d4e59d7daf8932fc1a`.
|
|
155
|
+
A fresh public-wheel venv passed default `prepare`, `check` and real stdio `smoke`,
|
|
156
|
+
selecting the expected MCP configuration ID without a local factory dependency.
|
|
157
|
+
That public installation rechecked the relocated receiver and rendered mapping.
|
|
158
|
+
The public gem installed into an isolated gem home and activated as 0.6.0 using
|
|
159
|
+
the runtime's existing Ruby dependencies; this is not a network-fresh dependency
|
|
160
|
+
installation claim. The downloaded candidate gem also passed isolated native
|
|
161
|
+
helper-closure inspection.
|
|
162
|
+
|
|
163
|
+
The source-only post-release branch `chore/80-pin-published-mcp-0.6.0` selects the
|
|
164
|
+
published MCP digest in `Makefile` and `scripts/unaltraweb-mcp-bootstrap.sh`, updates
|
|
165
|
+
the pin regression and current docs, and accompanies this report. Its PR/merge
|
|
166
|
+
and final clean-main confirmation are recorded in issue 80 after protected CI.
|
|
167
|
+
It does not rebuild or alter the published receipt, tag or packages.
|
|
168
|
+
|
|
169
|
+
The post-pin local recheck passed 587 Python cases (558 passed, 29 optional
|
|
170
|
+
skips), distribution/workflow/wheel and prose checks, `mcp-check`, real
|
|
171
|
+
`mcp-smoke` with the selected public PDF, docs build and whitespace checks.
|
|
172
|
+
Development builds used only `unaltraweb-closeout-060-*:post-pin` resources.
|
|
173
|
+
The actual `MCP_CONSUMER_WORKSPACE`-bound `make mcp-stdio` transport also initialized
|
|
174
|
+
a fresh synthetic consumer and exposed both native import tools; Docker inspection
|
|
175
|
+
confirmed the published MCP configuration ID above. Its retained result is
|
|
176
|
+
`/tmp/opencode/unaltraweb-closeout-060/post-pin-proof/evidence.json` and the session
|
|
177
|
+
exited normally. `mcp-build` and the bootstrap's `--check` selected the public
|
|
178
|
+
runtime directly.
|
|
179
|
+
|
|
180
|
+
Acceptance covers the exact Linux/amd64 tuple and published English one-page
|
|
181
|
+
Carta sample. The generic conformance tests do not establish Diapora composition
|
|
182
|
+
or other domain imports. Active IDE processes keep their loaded runtime until
|
|
183
|
+
reconnected. No real manual, author artifact, client registration or helper
|
|
184
|
+
selection was migrated. Consumer adoption and hub catalogue integration remain
|
|
185
|
+
separate owner actions; this report supplies their verified intake evidence.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Native retained-letter import — issue 80
|
|
2
|
+
|
|
3
|
+
Delivery completed on 2026-10-02; see [the 0.6.0 closeout](owner-closeout-80.md)
|
|
4
|
+
for final revisions, receipts, registry downloads and the post-release pin.
|
|
5
|
+
The following sections retain the chronological preparation and review evidence.
|
|
6
|
+
|
|
7
|
+
## Scope and release state
|
|
8
|
+
|
|
9
|
+
This is a separate 0.6.0 development increment after the administrative closeout
|
|
10
|
+
of issue 76. Gem, wheel, runtime, MCP and PDF worker are pending. The 0.5.1 release,
|
|
11
|
+
receipt and active checkout launcher pin remain unchanged. Consumer core/PDF
|
|
12
|
+
integration and publication need their own reviewed immutable selections. The
|
|
13
|
+
tested computation, capture and visual companion selections remain 0.4.0.
|
|
14
|
+
|
|
15
|
+
The native receiver accepts Carta 0.3.0rc1 leaf `letter-pdf-v1` units. It retains
|
|
16
|
+
the entire bundle, maps the original PDF byte for byte, creates a native draft
|
|
17
|
+
page/chapter and checks its source and rendered references. The manual PDF
|
|
18
|
+
builder includes all pages with `pdfpages`; every retained dependency and checker
|
|
19
|
+
contributes to freshness. Nothing executes the retained producer recipe.
|
|
20
|
+
Composite profiles, edited PDF variants and Diapora are outside this acceptance.
|
|
21
|
+
|
|
22
|
+
## Protocol and provenance
|
|
23
|
+
|
|
24
|
+
The wire v1 verifier and schema are byte-identical copies pinned to hub revision
|
|
25
|
+
`9167e3efb5968a64bb9100792163a179c1491860` (integration
|
|
26
|
+
`fc8745db950b04013c73eb49acf6781a26eb83f8`). Their respective SHA-256 values are
|
|
27
|
+
`48368035f242f4d4446cbbe1363f8a01a7c17fa164ffef21abadd878b288d82d` and
|
|
28
|
+
`b52a32b3bcfeed28cf34a9ec1557665a94466b51c451ccad47d2e87f6e23f9aa`.
|
|
29
|
+
No envelope fields were added. `binding.json` is a separate native record.
|
|
30
|
+
The integration actor identifies the importer by a hash of its code inventory,
|
|
31
|
+
not an invented or uncommitted Git revision.
|
|
32
|
+
|
|
33
|
+
Acceptance uses the final published
|
|
34
|
+
[Carta v0.3.0rc1 packet](https://github.com/dosquartsdedocs/unaltracarta/releases/tag/v0.3.0rc1),
|
|
35
|
+
revision `84258b6869689ea5f1a49a55abc2b865573fb512`:
|
|
36
|
+
|
|
37
|
+
| Artifact | SHA-256 |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| `distribution.json` | `9d94b918db086b445e4d8a3ece2435622e0f9f9893bcd50708b4d13f5ca0ad44` |
|
|
40
|
+
| `acceptance-0.3.0rc1.json` | `1bc7c467f3e35abf9fa5c27583dd8cc3ad4d4372f930c4be60ed142122158504` |
|
|
41
|
+
| `acceptance-0.3.0rc1.tar.gz` | `8764a717bda33e15b48b3a06fe6fbe5dc075abedf4fd52bd37fdf4ed70896179` |
|
|
42
|
+
| Published wheel | `0afab176ea0815d242f6e19021232bafdc63f9bb68cbacbd63b73f99b666b7c3` |
|
|
43
|
+
| Wheel bundle manifest | `aeaa757ee1be19bfe56dc9af8dd1178032929b4a2bec2dad2ebb621b158ad999` |
|
|
44
|
+
| Retained original PDF | `4a661740a18fe1cf75b84aa0d8532511fd105eb5484a5af700e11e8e30828ea4` |
|
|
45
|
+
|
|
46
|
+
The original producer job was
|
|
47
|
+
`.unaltracarta-handoff/jobs/a0794f7909a943eb844c87bb14002691/bundle/`.
|
|
48
|
+
Its renderer identity is
|
|
49
|
+
`sha256:ba2453fb42542433f68efd8888d628b95f256cefb9c545b3b35034d33296e340`.
|
|
50
|
+
The installed test authenticates the packet before bounded extraction and checks
|
|
51
|
+
every declared evidence file. Earlier release-candidate bytes are not inputs.
|
|
52
|
+
|
|
53
|
+
## Installed acceptance
|
|
54
|
+
|
|
55
|
+
`test/artifact_import_smoke.py` uses a wheel-installed CLI and Docker launcher,
|
|
56
|
+
without a host factory dependency. It creates a synthetic manual, imports the
|
|
57
|
+
published wheel bundle, edits surrounding prose, verifies an identical reimport
|
|
58
|
+
preserves that prose and removes both the extracted producer copy and incoming
|
|
59
|
+
copy. It then builds the web and PDF, checks the served page/PDF, moves the
|
|
60
|
+
receiver, runs both native and generic v1 checks, and explicitly rebuilds the
|
|
61
|
+
PDF in the moved receiver. Every original page must occur in order in the
|
|
62
|
+
composed PDF; comparison uses the original font encoding, including ligatures.
|
|
63
|
+
|
|
64
|
+
The passing local run is retained at
|
|
65
|
+
`/tmp/opencode/unaltraweb-import-80/installed-proof-final/evidence.json`.
|
|
66
|
+
Its receiver is `relocated-receiver/` in that directory. This is local owner
|
|
67
|
+
evidence from development images, not a signed release receipt.
|
|
68
|
+
|
|
69
|
+
| Tested identity | Value |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| Installed unaltraweb wheel SHA-256 | `407b1275d1de558da891f391454287d1b3e76fbef0e45460695e9731932b9e39` |
|
|
72
|
+
| Controller image ID | `sha256:81f1da616455c7378ba3400b9d638eb8e67fce9605f18353d49a796020d9b6fa` |
|
|
73
|
+
| PDF worker image ID | `sha256:b7b8f5b774a528cadb2ab7aa313b9ddbffa6d54c9d3b42bd6ff59a664be8ccf6` |
|
|
74
|
+
| Integration record SHA-256 | `79ede9c8701eedf6ca4f182dc4fd1c9df3b56581138c677e0315310d8b998d1c` |
|
|
75
|
+
| Composed PDF before and after relocation | `14b0ef586874704b6d1b045d6dde1f32ee08c8a9107006e06cfe2e8147f54621` |
|
|
76
|
+
|
|
77
|
+
The receiver retains all 12 seal files under
|
|
78
|
+
`.unaltraweb/artifacts/carta/bundle/`. Its mapping is
|
|
79
|
+
`payload/output/letter.pdf` → `assets/documents/carta.pdf`, with native content at
|
|
80
|
+
`_chapters/en/carta.md` and permalink `/en/retained/carta/` under `/letter-proof`.
|
|
81
|
+
The original one-page letter appears on page 10 of the 11-page composed manual.
|
|
82
|
+
Both web/HTTP checks passed; the non-web archive was absent from `_site`.
|
|
83
|
+
Generic verification after relocation passed with one bundle, one mapping and
|
|
84
|
+
14 verified files. Preview copies were cleaned through their exact receipts.
|
|
85
|
+
|
|
86
|
+
Intermediate failures are retained separately: missing explicit gem plugin
|
|
87
|
+
registration, an overly broad rendered-HTML scan, mismatched controller/worker
|
|
88
|
+
checker bytes, and an assertion that ignored the original PDF's ligature
|
|
89
|
+
encoding. Corrections preserve strict integrity/freshness gates. In particular,
|
|
90
|
+
the installed-image fixture force-reinstalls its supplied wheel even when its
|
|
91
|
+
development version equals the base image's version.
|
|
92
|
+
|
|
93
|
+
## Reproduction and boundaries
|
|
94
|
+
|
|
95
|
+
Prepare an installed wheel, the matching source-containing MCP image, and a PDF
|
|
96
|
+
worker built from the repository root with `scripts/manual/Dockerfile`. The test
|
|
97
|
+
controller in `test/artifact_import.Dockerfile` binds `MANUAL_PDF_IMAGE` to the
|
|
98
|
+
worker image ID. Then run:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python test/artifact_import_smoke.py \
|
|
102
|
+
--packet "$PUBLISHED_CARTA_PACKET" --output "$NEW_EVIDENCE_DIRECTORY" \
|
|
103
|
+
--cli "$INSTALLED/bin/unaltraweb-mcp" \
|
|
104
|
+
--launcher "$INSTALLED/bin/unaltraweb-mcp-docker" \
|
|
105
|
+
--image "$TEST_CONTROLLER" --pdf-image "$TEST_PDF_WORKER"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The output directory must not exist. Only copies created by the test are retired.
|
|
109
|
+
Unit-test bundles in `test/test_artifact_imports.py` are synthetic security and
|
|
110
|
+
transaction fixtures, not published-producer acceptance. They cover tampering,
|
|
111
|
+
incomplete resources, hidden references, symlinks/hardlinks, no-overwrite,
|
|
112
|
+
interruption/retry, generated-source ownership, PDF action aliases/chains,
|
|
113
|
+
rendered URL binding, native PDF inclusion and dependency closure.
|
|
114
|
+
|
|
115
|
+
The imported unit is portable because its seal, record, mapped PDF and content
|
|
116
|
+
all use receiver-relative paths. The integration does not depend on the incoming
|
|
117
|
+
directory, producer process, absolute source location or ignored recovery tree.
|
|
118
|
+
Failed publication retains prepared and partial files; there is no destructive
|
|
119
|
+
rollback. Reimport adopts only identical existing bytes and preserves authored
|
|
120
|
+
prose when the binding remains valid.
|
|
121
|
+
|
|
122
|
+
Final release gates must additionally bind the reviewed core/PDF consumer tuple
|
|
123
|
+
and same-source package/image candidates. A local acceptance run does not update
|
|
124
|
+
those pins, authenticate a public 0.6.0 release, authorize real-manual adoption,
|
|
125
|
+
or grant author approval to the draft content.
|
|
126
|
+
|
|
127
|
+
The gem and PDF worker include a regular Python package initializer and its
|
|
128
|
+
stdlib-only version/contract module. This prevents an unrelated installed wheel
|
|
129
|
+
from shadowing the gem's helpers. The extracted-gem gate asserts the actual
|
|
130
|
+
module paths. Checker code and schemas enter PDF freshness; the validated BOM's
|
|
131
|
+
worker/self pins do not, avoiding a worker that would need to contain its own
|
|
132
|
+
future digest. The integration actor separately hashes the full BOM metadata.
|
|
133
|
+
|
|
134
|
+
## Owner regression gates
|
|
135
|
+
|
|
136
|
+
- Python suite: 584 tests, 30 environment-dependent skips, no failures. The
|
|
137
|
+
focused importer suite covers 22 cases; the PDF builder suite covers 88.
|
|
138
|
+
- Ruby plugin suites: 64 tests and 334 assertions, no failures.
|
|
139
|
+
- Actual PDF toolchain integrations: 16 tests, no failures.
|
|
140
|
+
- `distribution-check`, `workflow-check`, `wheel-check`, `gem-check`,
|
|
141
|
+
`mcp-check`, `mcp-smoke`, `docs-build`, and fixed-epoch
|
|
142
|
+
`reproducible-site-check` passed on local owner resources. Distribution remains
|
|
143
|
+
structurally valid and explicitly not release-ready.
|
|
144
|
+
- The extracted-gem package gate exercises synthetic native retention using only
|
|
145
|
+
the gem's Python helper closure, with isolated Python and no wheel/core path.
|
|
146
|
+
Native deployment installs its parser dependencies before PDF/Jekyll checks.
|
|
147
|
+
- Populated Bundler roundtrip passed for `unaltreselfie`, `unaltreprojecte`,
|
|
148
|
+
`unaltredocs` and `unaltremanual`, with two builds and a preview per runtime.
|
|
149
|
+
It first reproduces the published unpatched 0.5.0 `google-protobuf (4.36.1)`
|
|
150
|
+
failure on a separate copy, then tests 0.4.0 → development 0.6.0 → 0.4.0.
|
|
151
|
+
The historical driver labels its patched step `fixed-050`; the recorded
|
|
152
|
+
image is the 0.6.0 test controller. All six retained author/cache paths keep
|
|
153
|
+
their initial hashes; no cache cleaning is used to obtain a pass.
|
|
154
|
+
|
|
155
|
+
Roundtrip evidence is retained at
|
|
156
|
+
`/tmp/opencode/unaltraweb-import-80/bundler-roundtrip-final/evidence.json`, using
|
|
157
|
+
the same final controller and worker IDs as the installed letter acceptance.
|
|
158
|
+
The source discovery descriptor additionally declares `.unaltraweb/artifacts`
|
|
159
|
+
as optional versioned source state with `cleanup: never`; `tmp` keeps its existing
|
|
160
|
+
ignored, explicit-cleanup policy. This final metadata-only addition is checked by
|
|
161
|
+
the path-policy and fresh-wheel gates and does not alter the tested import code.
|
|
162
|
+
|
|
163
|
+
## Closeout review — 2026-10-02
|
|
164
|
+
|
|
165
|
+
The owner explicitly authorized the full 0.6.0 commit/PR/integration, signed
|
|
166
|
+
candidate, gated publication and post-release pin flow. The session preflight
|
|
167
|
+
reported only the known unit-80 working tree and no competing session. Review
|
|
168
|
+
covered every tracked/untracked unit path; no unrelated changes were identified.
|
|
169
|
+
|
|
170
|
+
The two vendored protocol files match the exact established Git pin. The pinned
|
|
171
|
+
reference tests and fixture payloads were also checked (the later fixture README
|
|
172
|
+
only renames the integrated contract), and all 26 conformance tests pass. These
|
|
173
|
+
generic synthetic tests do not add a composite domain to the native importer.
|
|
174
|
+
The retained installed wheel/PDF hashes above and the moved receiver's native
|
|
175
|
+
web/PDF mapping were independently rechecked before editing.
|
|
176
|
+
|
|
177
|
+
Resolved review findings:
|
|
178
|
+
|
|
179
|
+
- Metadata could contain a local link or image while retained Pandoc evidence
|
|
180
|
+
remained stale. Renderable metadata now receives the independent text-reference
|
|
181
|
+
check; effective metadata rejects render-option fields outside the supported
|
|
182
|
+
author/stamp projection. Malformed Pandoc link evidence returns a structured
|
|
183
|
+
domain failure instead of an uncaught indexing error.
|
|
184
|
+
- A PDF OpenAction internal destination array was treated as an action array.
|
|
185
|
+
Internal destinations are supported while chained action arrays retain their
|
|
186
|
+
stricter checks. Regression tests cover both cases.
|
|
187
|
+
- The acceptance driver required a derived test-controller image. It now also
|
|
188
|
+
verifies the immutable PDF selection declared by the actual installed MCP image
|
|
189
|
+
and records the exact image references and source label, allowing signed bytes
|
|
190
|
+
to be exercised directly.
|
|
191
|
+
|
|
192
|
+
The corrected source passes 587 Python tests (30 optional skips), including 25
|
|
193
|
+
native import cases, plus distribution/workflow/fresh-wheel gates. The historical
|
|
194
|
+
local evidence above remains retained; signed-candidate and public-download
|
|
195
|
+
acceptance must record their own revisions and hashes. The consumer core/PDF
|
|
196
|
+
tuple is closed only after the reviewed integrated core and signed PDF digest
|
|
197
|
+
exist; no guessed source or self-digest is inserted into the BOM.
|
|
198
|
+
|
|
199
|
+
## Reviewed immutable consumer tuple
|
|
200
|
+
|
|
201
|
+
PR [81](https://github.com/dosquartsdedocs/unaltraweb/pull/81) integrated reviewed
|
|
202
|
+
implementation `7af652fb83629e959af05c407a34a2f5a15f7936` as
|
|
203
|
+
`5cf9817489c8dc47cee726bfe42fe3071cd32b85`. Protected PR CI
|
|
204
|
+
[37027921742](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37027921742)
|
|
205
|
+
and CodeQL [37027922332](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37027922332)
|
|
206
|
+
passed, followed by integrated-source CI
|
|
207
|
+
[37028677932](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37028677932)
|
|
208
|
+
and CodeQL [37028678347](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37028678347).
|
|
209
|
+
The PR contains an explicit agent review, not an attributed human approval.
|
|
210
|
+
|
|
211
|
+
Signed image workflow
|
|
212
|
+
[37029374441](https://github.com/dosquartsdedocs/unaltraweb/actions/runs/37029374441)
|
|
213
|
+
then published, attested and tested the PDF from that exact source. Its read-only
|
|
214
|
+
test job verified the signer workflow/source digest before executing the exact
|
|
215
|
+
image, including 16 PDF integrations and real MCP preparation. The selected
|
|
216
|
+
PDF 0.6.0 identity is
|
|
217
|
+
`ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:0ba267cb87f53ebaca4e31805fe00610cd61fdf97a8d2c3692f4655700dceaed`.
|
|
218
|
+
The BOM and Make contract now select that same digest and integrated core SHA.
|
|
219
|
+
|
|
220
|
+
That public signed PDF is recorded as `released` and reused by digest. The four
|
|
221
|
+
core/package components are `ready` for final same-commit candidates; their strict
|
|
222
|
+
gate still requires a new receipt-only child of the final artifact source.
|
|
223
|
+
Subsequent verification-only PDF builds are not substituted for this selected
|
|
224
|
+
worker or promoted under an assumed identity. The earlier 0.5.1 receipt and
|
|
225
|
+
active launcher pin remain intact until the authorized 0.6.0 closeout completes.
|
|
226
|
+
|
|
227
|
+
The tuple was exercised before its pin PR using an installed wheel and a local
|
|
228
|
+
MCP containing the new BOM with the actual signed PDF above. Evidence is retained
|
|
229
|
+
at `/tmp/opencode/unaltraweb-closeout-060/tuple-letter-proof/evidence.json`:
|
|
230
|
+
integration `ebe07ee10ad740a2bbbd36d532f336374cf4bb19ccb373b6590b2279f664a222`,
|
|
231
|
+
composed PDF `416e96f66bb6608b1e20bf5e36b6b16133bd4018c17e6c079e8987b736fe9cae`
|
|
232
|
+
both before and after the forced relocated rebuild. The PDF's inspected local
|
|
233
|
+
image ID is `sha256:d7e7d3243616270fc9e6eed7f8238c412dbe3d9ffc18d2832d17d66ca630d139`,
|
|
234
|
+
with the exact integrated source revision label. This preparation proof does not
|
|
235
|
+
substitute for the final signed MCP and downloaded package acceptance.
|
data/lib/unaltraweb.rb
CHANGED
data/requirements.txt
CHANGED
data/scripts/manual/Dockerfile
CHANGED
|
@@ -23,9 +23,12 @@ RUN printf '%s\n' \
|
|
|
23
23
|
&& rm -rf /var/lib/apt/lists/* \
|
|
24
24
|
&& pip install --no-cache-dir PyYAML==6.0.2
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
COPY
|
|
28
|
-
COPY
|
|
29
|
-
COPY
|
|
26
|
+
RUN pip install --no-cache-dir 'pypdf>=6,<7' 'markdown-it-py>=3,<5'
|
|
27
|
+
COPY scripts/manual/build_pdf.py /opt/unaltraweb/manual/build_pdf.py
|
|
28
|
+
COPY scripts/manual/Dockerfile /opt/unaltraweb/manual/Dockerfile
|
|
29
|
+
COPY scripts/manual/filters /opt/unaltraweb/manual/filters
|
|
30
|
+
COPY scripts/manual/templates /opt/unaltraweb/manual/templates
|
|
31
|
+
COPY src/unaltraweb_mcp/__init__.py src/unaltraweb_mcp/distribution.py src/unaltraweb_mcp/component-contract.json src/unaltraweb_mcp/component-contract.schema.json src/unaltraweb_mcp/artifact_handoff_v1.py src/unaltraweb_mcp/artifact-handoff-v1.schema.json src/unaltraweb_mcp/artifact_imports.py src/unaltraweb_mcp/letter_bundle.py src/unaltraweb_mcp/pdf_probe.py src/unaltraweb_mcp/processes.py /opt/unaltraweb/src/unaltraweb_mcp/
|
|
32
|
+
ENV PYTHONPATH=/opt/unaltraweb/src
|
|
30
33
|
|
|
31
34
|
ENTRYPOINT ["python3", "/opt/unaltraweb/manual/build_pdf.py"]
|
data/scripts/manual/build_pdf.py
CHANGED
|
@@ -26,6 +26,10 @@ except ImportError as exc: # pragma: no cover - supplied by the builder image
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
SCRIPT_ROOT = Path(__file__).resolve().parent
|
|
29
|
+
for _source_root in (SCRIPT_ROOT.parent.parent / "src", SCRIPT_ROOT.parent / "src"):
|
|
30
|
+
if (_source_root / "unaltraweb_mcp" / "artifact_imports.py").is_file():
|
|
31
|
+
sys.path.insert(0, str(_source_root))
|
|
32
|
+
break
|
|
29
33
|
DEFAULT_DOCKERFILE = SCRIPT_ROOT / "Dockerfile"
|
|
30
34
|
DEFAULT_TEMPLATE = SCRIPT_ROOT / "templates" / "manual.tex"
|
|
31
35
|
DEFAULT_BIBLIOGRAPHY_FILTER = SCRIPT_ROOT / "filters" / "bibliography.lua"
|
|
@@ -36,6 +40,7 @@ BIB_CUSTOM_URL_RE = re.compile(r'(?im)^\s*(?:manual_url|website)\s*=\s*(?:\{([^}
|
|
|
36
40
|
FRONT_MATTER_RE = re.compile(r"\A---[ \t]*\r?\n(.*?)^---[ \t]*(?:\r?\n|\Z)", re.MULTILINE | re.DOTALL)
|
|
37
41
|
CITE_RE = re.compile(r"{%\s*cite\s+([^%]+?)\s*%}")
|
|
38
42
|
INCLUDE_RE = re.compile(r"{%\s*include\s+([^%]+?)\s*%}")
|
|
43
|
+
RETAINED_DOCUMENT_RE = re.compile(r"{%\s*retained_document\s+([a-z][a-z0-9-]{0,63})\s*%}")
|
|
39
44
|
LIQUID_RE = re.compile(r"({[{%].*?[}%]})", re.DOTALL)
|
|
40
45
|
INLINE_CODE_RE = re.compile(r"<code>(.*?)</code>", re.IGNORECASE | re.DOTALL)
|
|
41
46
|
FENCED_CODE_BLOCK_RE = re.compile(r"^[ \t]*(`{3,}|~{3,})[^\n]*\n.*?^[ \t]*\1[ \t]*$", re.MULTILINE | re.DOTALL)
|
|
@@ -947,6 +952,17 @@ def transform_markdown(
|
|
|
947
952
|
citation_keys.extend(key for key in keys if key not in citation_keys)
|
|
948
953
|
return "[" + "; ".join(f"@{key}" for key in keys) + "]"
|
|
949
954
|
|
|
955
|
+
def retained_document(match: re.Match[str]) -> str:
|
|
956
|
+
from unaltraweb_mcp.artifact_imports import check_imports
|
|
957
|
+
|
|
958
|
+
result = check_imports(project, match.group(1))
|
|
959
|
+
if result.get("ok") is not True:
|
|
960
|
+
raise ManualPdfError(f"Retained document verification failed: {result.get('error')}")
|
|
961
|
+
path = result["imports"][0]["pdf"]
|
|
962
|
+
# The native import layout uses an ASCII slug and fixed project-relative
|
|
963
|
+
# path; no bundle text is interpolated into TeX or executed.
|
|
964
|
+
return protect("```{=latex}\n\\includepdf[pages=-,pagecommand={}]" + "{" + path + "}\n```")
|
|
965
|
+
|
|
950
966
|
def table(match: re.Match[str]) -> str:
|
|
951
967
|
body = match.group("body").strip()
|
|
952
968
|
credit, _ = caption_source_attribute(match.group("attrs") or "")
|
|
@@ -1137,6 +1153,7 @@ def transform_markdown(
|
|
|
1137
1153
|
transformed = transformed.replace(r"\begin{equation\*}", r"\begin{equation*}")
|
|
1138
1154
|
transformed = transformed.replace(r"\end{equation\*}", r"\end{equation*}")
|
|
1139
1155
|
transformed = BASEURL_RE.sub("", transformed)
|
|
1156
|
+
transformed = RETAINED_DOCUMENT_RE.sub(retained_document, transformed)
|
|
1140
1157
|
transformed = transformed.replace("{% include manual-bibliography.liquid %}", "::: {#refs}\n:::")
|
|
1141
1158
|
transformed = CITE_RE.sub(citations, transformed)
|
|
1142
1159
|
transformed = CALLOUT_BLOCK_RE.sub(callout, transformed)
|
|
@@ -1481,6 +1498,17 @@ def build_dependencies(project: Path, metadata: dict[str, Any], source_paths: li
|
|
|
1481
1498
|
]
|
|
1482
1499
|
for path in source_paths:
|
|
1483
1500
|
dependencies.append((f"source:{path.relative_to(project)}", path))
|
|
1501
|
+
if any(RETAINED_DOCUMENT_RE.search(path.read_text(encoding="utf-8")) for path in source_paths if path.suffix.lower() == ".md"):
|
|
1502
|
+
from unaltraweb_mcp import artifact_imports
|
|
1503
|
+
|
|
1504
|
+
imports = artifact_imports.check_imports(project)
|
|
1505
|
+
if imports.get("ok") is not True:
|
|
1506
|
+
raise ManualPdfError(f"Retained document verification failed: {imports.get('error')}")
|
|
1507
|
+
for item in imports["imports"]:
|
|
1508
|
+
dependencies.extend((f"retained:{relative}", project / relative) for relative in item["inputs"])
|
|
1509
|
+
checker_root = Path(artifact_imports.__file__).parent
|
|
1510
|
+
for name in artifact_imports.CHECKER_FILES:
|
|
1511
|
+
dependencies.append((f"import-check:{name}", checker_root / name))
|
|
1484
1512
|
if csl:
|
|
1485
1513
|
dependencies.append((f"csl:{csl.relative_to(project)}", csl))
|
|
1486
1514
|
for key in ["cover-image", "cover-logo", "series-logo"]:
|
data/scripts/test_gem_build.py
CHANGED
|
@@ -64,6 +64,9 @@ def inspect_gem(path: Path) -> None:
|
|
|
64
64
|
editorial_files = ["scripts/editorial_check.py", "src/unaltraweb_mcp/editorial.py", "src/unaltraweb_mcp/editorial_sources.py"]
|
|
65
65
|
inspection_files = editorial_files + ["src/unaltraweb_mcp/bundler_runtime.py", "scripts/image_background_check.py", "src/unaltraweb_mcp/image_backgrounds.py",
|
|
66
66
|
"src/unaltraweb_mcp/image_probe.py", "src/unaltraweb_mcp/processes.py"]
|
|
67
|
+
inspection_files += [f"src/unaltraweb_mcp/{name}" for name in (
|
|
68
|
+
"__init__.py", "distribution.py", "component-contract.json", "component-contract.schema.json",
|
|
69
|
+
"artifact_imports.py", "artifact_handoff_v1.py", "artifact-handoff-v1.schema.json", "letter_bundle.py", "pdf_probe.py")]
|
|
67
70
|
with tarfile.open(path, mode="r") as package:
|
|
68
71
|
data_member = package.extractfile("data.tar.gz")
|
|
69
72
|
if data_member is None:
|
|
@@ -83,6 +86,7 @@ def inspect_gem(path: Path) -> None:
|
|
|
83
86
|
"_plugins/figure_captions.rb",
|
|
84
87
|
"_plugins/manual_release_metadata.rb",
|
|
85
88
|
"_plugins/reproducible_build_time.rb",
|
|
89
|
+
"_plugins/retained_documents.rb",
|
|
86
90
|
"assets/js/content-search-match.js",
|
|
87
91
|
"assets/js/content-search.js",
|
|
88
92
|
"_config.yml",
|
|
@@ -134,6 +138,29 @@ def inspect_gem(path: Path) -> None:
|
|
|
134
138
|
inspection = json.loads(run(image_command, cwd=site).stdout)
|
|
135
139
|
if not inspection["ok"] or inspection["images"][0]["state"] != "transparent" or not inspection["warnings"]:
|
|
136
140
|
raise RuntimeError(f"Gem-native SVG background inspection failed: {inspection}")
|
|
141
|
+
# This is the synthetic domain fixture, not published-Carta acceptance.
|
|
142
|
+
# Only its data crosses into the isolated extracted-gem subprocess.
|
|
143
|
+
sys.path.insert(0, str(ROOT / "test"))
|
|
144
|
+
from test_artifact_imports import fixture
|
|
145
|
+
|
|
146
|
+
bundle_sha, template_sha = fixture(site / "incoming/letter")
|
|
147
|
+
(site / ".gitignore").write_text("tmp/\n", encoding="utf-8")
|
|
148
|
+
run(["git", "init", "--quiet"], cwd=site)
|
|
149
|
+
isolated = """
|
|
150
|
+
import json, sys
|
|
151
|
+
from pathlib import Path
|
|
152
|
+
sys.path.insert(0, sys.argv[1])
|
|
153
|
+
from unaltraweb_mcp import artifact_imports, letter_bundle, artifact_handoff_v1, distribution, processes
|
|
154
|
+
for module in (artifact_imports, letter_bundle, artifact_handoff_v1, distribution, processes):
|
|
155
|
+
assert Path(module.__file__).is_relative_to(Path(sys.argv[1])), module.__file__
|
|
156
|
+
letter_bundle.TEMPLATES['default-letter.latex'] = sys.argv[4]
|
|
157
|
+
project = Path(sys.argv[2])
|
|
158
|
+
result = artifact_imports.import_bundle(project, 'incoming/letter/bundle.json', sys.argv[3],
|
|
159
|
+
'letter', '_pages/en/letter.md', dry_run=False, confirm_import=True)
|
|
160
|
+
print(json.dumps(result))
|
|
161
|
+
raise SystemExit(0 if result['ok'] else 1)
|
|
162
|
+
"""
|
|
163
|
+
run([sys.executable, "-I", "-c", isolated, str(core / "src"), str(site), bundle_sha, template_sha], cwd=site)
|
|
137
164
|
|
|
138
165
|
|
|
139
166
|
def main() -> int:
|
|
@@ -90,6 +90,11 @@ def main() -> int:
|
|
|
90
90
|
required = [
|
|
91
91
|
"unaltraweb_mcp/calibre_import.py",
|
|
92
92
|
"unaltraweb_mcp/bundler_runtime.py",
|
|
93
|
+
"unaltraweb_mcp/artifact_imports.py",
|
|
94
|
+
"unaltraweb_mcp/artifact_handoff_v1.py",
|
|
95
|
+
"unaltraweb_mcp/artifact-handoff-v1.schema.json",
|
|
96
|
+
"unaltraweb_mcp/letter_bundle.py",
|
|
97
|
+
"unaltraweb_mcp/pdf_probe.py",
|
|
93
98
|
"unaltraweb_mcp/component-contract.json",
|
|
94
99
|
"unaltraweb_mcp/component-contract.schema.json",
|
|
95
100
|
"unaltraweb_mcp/manual_pdf_preview.py",
|
|
@@ -137,14 +142,14 @@ def main() -> int:
|
|
|
137
142
|
fake_bin = temp / "fake-bin"
|
|
138
143
|
fake_bin.mkdir()
|
|
139
144
|
fake_docker = fake_bin / "docker"
|
|
140
|
-
fake_docker.write_text("#!/bin/sh\n[ \"$1 $2\" = 'image inspect' ] || exit 99\n[ \"$5\" = \"$EXPECTED_IMAGE\" ] || exit 98\nprintf 'sha256:
|
|
145
|
+
fake_docker.write_text("#!/bin/sh\n[ \"$1 $2\" = 'image inspect' ] || exit 99\n[ \"$5\" = \"$EXPECTED_IMAGE\" ] || exit 98\nprintf 'sha256:1111111111111111111111111111111111111111111111111111111111111111\\n'\n", encoding="utf-8")
|
|
141
146
|
fake_docker.chmod(0o755)
|
|
142
147
|
expected_image = json.loads((ROOT / "src/unaltraweb_mcp/component-contract.json").read_text())["components"]["mcp"]["reference"]
|
|
143
148
|
launcher_env = {**no_consumer_env, "PATH": f"{fake_bin}:{env['PATH']}", "EXPECTED_IMAGE": expected_image}
|
|
144
149
|
launcher_env.pop("UNALTRAWEB_MCP_IMAGE", None)
|
|
145
150
|
launcher_env.pop("MCP_RELEASE_IMAGE", None)
|
|
146
151
|
prepared_image = run([str(docker_cli), "prepare"], cwd=temp, env=launcher_env).stdout.strip()
|
|
147
|
-
if prepared_image != "sha256:
|
|
152
|
+
if prepared_image != "sha256:" + "1" * 64:
|
|
148
153
|
raise RuntimeError("Installed preparation did not use the packaged bootstrap")
|
|
149
154
|
run(["make", "--silent", "--no-print-directory", "-C", str(launcher), "mcp-build"], cwd=temp, env=launcher_env)
|
|
150
155
|
run([str(docker_cli), "prepare", "--image", "explicit:override"], cwd=temp,
|