unaltraweb 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: acaf4cf39c6e712f16e9815d41d137e94972a0224fb685d19fe36c3f82a7a195
4
- data.tar.gz: fc287067a780f72c8d51ec287a889767cdce5420557733aff7a5e988fa17e45a
3
+ metadata.gz: 66c0a140c30b1c7d9f1353efc62b28eb3c379649160ba68ad6b262d1f91ec90a
4
+ data.tar.gz: f6d0c69a53d4b1a5de92777335c6cd1705f4946fb6390cac260fcbeac7db3361
5
5
  SHA512:
6
- metadata.gz: 98a42d39c19df577bb5c69b08d2b20abdfa283d38e18dbbd45239cd7a887f0c43615b3d5a5d614f77f37f309b92aaaed666a5b90863a23595ff1e03f91e15de4
7
- data.tar.gz: 765b280a1315f2be24e6bfc6894d5dc9f394ce201ccce86d7a994a6643e518bc45aceec473fea77d2e5cd3bf647031ca1a4943a72c9470b8d6607c53f0843bb9
6
+ metadata.gz: d3dff0655f66a91f8a56c301c2da3fd395ef4b2ef7cd33e80a2c858a86cb3a734058480d62bdfc7753663d93b44f2906076c8ce74a2504de1295856ae2b1cf04
7
+ data.tar.gz: 9e8ffdb6047bde3d209f47fe339dcb97fe3d60ca365468cc7a056860b041c7e1823b9c47e7974da3f20e7be0e0c0719f986a617318876f64556e551c169a71e6
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.2
5
- MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.2
6
- MCP_RELEASE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:6aa20cff86c3891a876e37ba0548fa36f3c5633c9f22ba672e9f50123d677cf6
4
+ MCP_RUNTIME_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.7.4
5
+ MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.4
6
+ MCP_RELEASE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:8183e7117f5902fc0ad4d930b757d874b2da1f93d5ef4db102ae4c1b03e357a3
7
7
  MCP_DOCKER_BUILD_NETWORK ?= default
8
8
  INIT_SITE_PROFILE ?= unaltreselfie
9
9
  NEW_WEB_PROFILE ?= unaltreselfie
@@ -40,7 +40,7 @@ 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.2
43
+ DOCKER_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.7.4
44
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)
data/README.md CHANGED
@@ -34,7 +34,7 @@ The default distribution is Docker-first. Generated sites run their normal build
34
34
 
35
35
  ## Current Status
36
36
 
37
- - Public release [`v0.5.0`](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.5.0) provides the Docker images, Ruby gem and Python wheel as one receipt-bound distribution.
37
+ - Published releases provide receipt-bound Docker images, Ruby gems and Python wheels. The 0.7.4 source unit corrects the native core/gem tuple and adds reviewed scaffold conflict resolution; see [the acceptance and migration record](docs/agents/scaffold-closeout-118.md) for publication status and exact boundaries.
38
38
  - `ghcr.io/dosquartsdedocs/unaltraweb-mcp` is the canonical normal local runtime for generated sites; `ghcr.io/dosquartsdedocs/unaltraweb` is its lower-level Jekyll runtime base.
39
39
  - The Ruby gem supports native Bundler/Jekyll consumers. The modular MCP wheel supports native creation and inspection, and does not bundle the gem, factory checkout, worker images or companion renderers.
40
40
  - PDF, browser-capture and computation environments remain separate images so the normal site image does not carry every heavy toolchain.
@@ -25,6 +25,23 @@ The template is the better place to validate gem consumption, centralized styles
25
25
 
26
26
  ## Component Contract
27
27
 
28
+ ### Coherent core pins and reviewed scaffold updates
29
+
30
+ The 0.7.4 source contract distinguishes the package release from the gem version
31
+ at the selected Git core. `consumer_integration.core_gem_version` drives the native
32
+ Gemfile and lock, while the controller and reusable workflow retain independent
33
+ pins. Source checks inspect the real referenced Git contract; installed acceptance
34
+ resolves and builds that core with Bundler rather than comparing generated text.
35
+
36
+ Conflicting managed ignore/workflow files can use explicit hash-bound reviews.
37
+ The provider proposes conservative `keep`, `prepend-package` and `pins-only`
38
+ results; it never accepts an arbitrary replacement or ignores a conflict.
39
+ Local ignore order/negations and workflow controls are preserved, and stale
40
+ reviews fail before mutation. The same manifest-last transaction and recovery
41
+ guards apply. Subsequent plans retain the customization visibly.
42
+ See the [owner migration record](https://github.com/dosquartsdedocs/unaltraweb/blob/main/docs/agents/scaffold-closeout-118.md)
43
+ for the plan/review/apply sequence, acceptance and publication status.
44
+
28
45
  ### Published 0.7.1 release
29
46
 
30
47
  [**0.7.1**](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.7.1)
@@ -333,7 +333,21 @@ source conservation and retained-input/domain validation. See
333
333
 
334
334
  At session start, `site_context.update_status` supplies an offline advisory against the active MCP package, including current literal version pins, target integration tuple, planned paths, preserved files, conflicts and `plan_sha256`. The agent explains available updates and asks for explicit acceptance before invoking `scaffold_sync` with that digest as `expected_plan_sha256`. The digest binds the consumer path, configuration, baseline, observed managed bytes and target package bytes; stale approval is rejected before writes. The parameter is optional for compatibility with existing explicit sync callers, but the guided flow always supplies it. An update can refresh scaffold controls without claiming a newer semver release. Unmanaged sites report an unavailable plan instead of being reinitialized. A declined update leaves normal content work available; there is no background network poll, self-upgrade, Git operation or automatic artefact regeneration. This flow requires a reviewed MCP/package release containing it and a reconnected client; updating the discovery checkout alone cannot replace the public digest-pinned runtime.
335
335
 
336
- Planning, version comparisons, conflict/preservation decisions and replacement bytes are deterministic code, also callable through the CLI without an agent. The agent controls invocation, explanation, collection of user acceptance and Git/review orchestration; the server cannot guarantee that an agent will present the startup offer. No LLM generates managed replacements or resolves conflicts within `scaffold_sync`. The plan is repeatable for the same bound path and input bytes; diagnostic time in the surrounding `site_context` response does not enter its digest.
336
+ Planning, version comparisons, conflict/preservation decisions and replacement bytes are deterministic code, also callable through the CLI without an agent. The agent controls invocation, explanation, collection of user acceptance and Git/review orchestration; the server cannot guarantee that an agent will present the startup offer. No LLM generates managed replacement bytes within `scaffold_sync`. The plan is repeatable for the same bound path and input bytes; diagnostic time in the surrounding `site_context` response does not enter its digest.
337
+
338
+ From 0.7.4, `scaffold_sync(..., review=...)` exposes a bounded reviewed-resolution
339
+ path. Conflicted plans return `review_inputs` and deterministic `resolution_options`.
340
+ The versioned `unaltraweb-scaffold-review` binds the original `base_plan_sha256`,
341
+ each path/mode, baseline/local/payload/result hashes and a review reason. Supported
342
+ modes retain all local ignore bytes (`keep` or package-before-local
343
+ `prepend-package`) or update only defined workflow scalar pins (`pins-only`),
344
+ preserving mandatory controls and unrelated local behavior. Missing/unsafe paths,
345
+ unknown modes and version guards cannot be overridden. The resolved dry-run has
346
+ its own hash, mandatory on apply together with the same review and confirmation.
347
+ The manifest records the real upstream baseline and reviewed-result receipts;
348
+ subsequent plans remain honest about customization. CLI uses `--review-json JSON`.
349
+ See [scaffold-closeout-118.md](scaffold-closeout-118.md) for the public migration
350
+ sequence and the independently selected native `core_gem_version`.
337
351
 
338
352
  Each scaffold is already reduced to one profile, so `profile_prune_plan` is not part of new-site creation. The prune rule remains available for existing mixed-profile sites.
339
353
 
@@ -0,0 +1,156 @@
1
+ # Web #109 — QGIS 0.6.1 compatibility point
2
+
3
+ Web **0.7.3 is published and verified**, with real consumer adoption remaining
4
+ separate. This maintenance point changes the exact external private-QGIS
5
+ dependency from 0.6.0 to 0.6.1. Published Web 0.7.2 remains immutable.
6
+
7
+ Provider handoff: [Web #109](https://github.com/dosquartsdedocs/unaltraweb/issues/109#issuecomment-6283746978).
8
+ Hub preparation: [gaContExt #38](https://github.com/dosquartsdedocs/gacontext/issues/38#issuecomment-6301327451).
9
+ The latter has prepared/enrolled QGIS independently; it has not selected this new
10
+ Web point or changed a real consumer cohort.
11
+
12
+ ## Published delivery
13
+
14
+ [Release v0.7.3](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.7.3)
15
+ was published at `2026-10-21T00:18:07Z`. Source PR110 and the two-line release-runner
16
+ correction PR111 produced artifacts from `9d97197dec5fc9346ab795191a3afd18884c27fb`.
17
+ Receipt-only PR112 integrated at `bff69e372b623ffba880be3d075bcc6f07d8c82b`, with
18
+ that source as its first parent and no other file change. Annotated tag object:
19
+ `5faa7bbd4d00994032f7b15b2d3aee7c8d836346`.
20
+
21
+ The [machine-readable handoff](https://github.com/dosquartsdedocs/unaltraweb/releases/download/v0.7.3/release-handoff.json)
22
+ has 13578 bytes and SHA-256
23
+ `bd2962be42f296df856430a4e31c8aae6daf17f6858e4aaf240712da49cbb585`.
24
+ It contains the complete credential-free artifact URLs, sizes, hashes, independent
25
+ worker provenance, native selector roles and acceptance limits.
26
+
27
+ | Published component | Identity |
28
+ | --- | --- |
29
+ | Web receipt | `7b3c8b12734554d60ae212d88028132ee982f96b8f9465b75a1ea84ad3e71f9e` |
30
+ | Wheel, 286769 bytes | `bb27901e03063280f06be282559fefeb936c5350ace9c5d4ee9f322d57539af7` |
31
+ | Gem, 33491456 bytes | `80886c7195bd6f6fa4b1c90f808864769d392abfdbc4deca3e7cadafae96589a` |
32
+ | MCP registry digest | `sha256:8183e7117f5902fc0ad4d930b757d874b2da1f93d5ef4db102ae4c1b03e357a3` |
33
+ | MCP configuration ID | `sha256:0a5b91a4c1c8b3b0bd8d3c4160ed1e5b9ccc8ad3cd0abee67f621d8636d15bd6` |
34
+ | Base runtime registry digest | `sha256:fd23c62f31b4c0a612a17bfbbb93990dad367f261b415607b90219847efbf67a` |
35
+ | Base runtime configuration ID | `sha256:6a067fc0de6054e7e882ffb5f84dc39709a4a6f3b2fe6ddf9817339085873564` |
36
+
37
+ Signed candidate workflow `39516559493`, package preparation `39516559072`,
38
+ receipt PR CI `39518426989`, tag CI `39519357013`, image promotion `39519454438`
39
+ and Trusted Publishing `39519455129` pass. All source PRs used protected normal
40
+ merges and explicit owner technical reviews. Copilot returned quota exhaustion;
41
+ no independent human or completed Copilot approval is claimed.
42
+
43
+ All 17 final GitHub assets, both registry packages, OCI aliases, configuration IDs
44
+ and source labels were verified anonymously. The previous 17 Web 0.7.2 assets and
45
+ its annotated tag remain identical. Final candidate synthetic acceptance:
46
+ `ec07eef91c66411e166c0117b3a205491198bf2342776c8087eb647f5ad4c906`.
47
+ A fresh launcher installed from the public GitHub wheel then passed real MCP
48
+ resource reads, complete package-file equality, binding, no drift, limits and
49
+ drain/EOF/exact absence:
50
+ `849c38b70a8b634fb0757357747522b8e60769f29819f5c75365dd674693152e`.
51
+ The earlier local preparation records below remain historical evidence.
52
+
53
+ The post-release checkout selector uses the published MCP digest above. This is
54
+ a later source-only pin, not a rebuild or alteration of the immutable tag/receipt.
55
+ No global/consumer registration or existing connection was replaced.
56
+
57
+ ## Exact private dependency
58
+
59
+ All inputs below were downloaded through authenticated GitHub acquisition into
60
+ ignored `tmp/qgis-061-adoption-109/assets/`, then checked by bytes and SHA-256.
61
+ Only the public metadata descriptor travels in Web; no private source, wheel,
62
+ archive or credentials are included in the public wheel or image.
63
+
64
+ | Identity | Value |
65
+ | --- | --- |
66
+ | QGIS source/tag | `1ca6ed95195d44097057d7165dc5dc0730cdf1c0`, `v0.6.1` |
67
+ | External `release.json` | 1251 bytes, `c09148927767855e6694e246ae38a9bdda4181086d18f78c204999648ec1089c` |
68
+ | Private wheel | 334648 bytes, `89998d9e41dcc90b8768ac036bf480e3501138d715824e12f928ab15f75dfbb7` |
69
+ | Private two-image archive | 1372056314 bytes, `fa870962e40bf416aeea262047b32a148bb3a73f8ae2dff6cbd4b20426453d1d` |
70
+ | Controller configuration ID | `sha256:d06b742c3e7d2e9383cf8a1d22bce928dd806f316a0bcbb1f676f50e22e94b05` |
71
+ | Auxiliary QGIS engine | `sha256:1003721d96abe9607d8337b36851f9b29f84c2f8f92b377d1a73ff03c9d15cd2` |
72
+ | Release producer revision | `sha256:35443a3343f403892b387c1622656ff3a242044b890fe4ea0cd1e66dd52653e1` |
73
+ | Native `practice-schema` revision | `sha256:4604801be887a19747aa74c84a2d99141308fadde44f5cddacb4d821b6861398` |
74
+ | Separately scoped published D0 code revision | `sha256:8e5f451cd0669c80e17c6b1b72f3e22dce53dbd405098ef67f6980cf759553bc` |
75
+ | Web descriptor SHA-256 | `8f2ff3531ad2a65fab9992ac5ef01d3cec65b88625ee26d5b2149be8ad065b99` |
76
+
77
+ The canonical private receipt URL is
78
+ `https://github.com/dosquartsdedocs/unaltracaptura-qgis/releases/download/v0.6.1/release.json`.
79
+ Its source, version, producer, wheel and two images match the Web declaration.
80
+ The archive checksum, both configuration hashes, platform and declared layer
81
+ presence were checked without extracting/loading/retagging the archive.
82
+ The controller OCI source label remains actually absent (`null`), not the Git SHA.
83
+
84
+ The native practice fingerprint is **4604801b…**, observed both through the
85
+ installed provider CLI and inside its pinned controller. The D0 fingerprint
86
+ **8e5f451c…** cannot replace it: an initial schema probe using that other scope
87
+ was refused. Both v1/v2 probes pass with the native practice revision. Regression
88
+ tests reject the old 0.6.0 revision, the D0 revision and the release producer as
89
+ substitutes. The schema hashes remain respectively
90
+ `9bc7f15ede9d67b3e1209c329da13d9fcb08004090d05b27662a43de6edf3445` and
91
+ `528c8be229c72c346f134ffaa60094f94224094a25b6fb11bcc87802ddc7fffb`.
92
+
93
+ `practice_verifier` remains the Web startup worker role. `engine.image_id` is the
94
+ separate QGIS auxiliary, checked before native reopen, not a `qgis` entry in Web
95
+ `--worker-images`. The bridge and lifecycle implementation are unchanged.
96
+ PDF 0.7.1, its producer `b7ec1d7a139c65b3b0b88699cdbeb19080f13be1`, core/workflow
97
+ `3332e0b93933f12317e05f1ce8d38ce80046feab`, Dia 0.5.0 and Vega 0.5.1 retain their
98
+ independent selections. Public CI reports private execution as `not_run`.
99
+
100
+ ## Local synthetic acceptance
101
+
102
+ `test/qgis_compatibility_smoke.py` accepts explicit already-acquired inputs and
103
+ immutable image IDs. Its only GIS input is the provider's pinned
104
+ `examples/portable-practice/`: two invented projected points, an 80 m buffer and
105
+ a 32×24 synthetic raster. No manual, real dataset or existing screenshot is used.
106
+ The provider example stays outside Git/public packages and its source blobs and
107
+ hashes are retained alongside the downloaded inputs.
108
+
109
+ The complete passing run is
110
+ `tmp/qgis-061-adoption-109/local-acceptance-03/evidence.json`, SHA-256
111
+ `3122e0751813ad24f0f2456adae84c792f7d3b0693bc504f3d9d73a30201a6fc`.
112
+
113
+ - Local Web-only image: `sha256:765b10855cc70f5cdaf18d998bac8cdbe60621c3a8fcbc90f66bca8a02c0dfc7`.
114
+ - Local wheel: `14fca099e7b725a0041f42bc32dfdb80bc34c454d5983bfda9ffbc090fe17827`.
115
+ - Descriptor bytes match the source, built wheel and installed Web image.
116
+ - Real MCP initialization, both practice `resources/read`, worker identity and
117
+ dry-run/actual composition pass with the fresh installed host launcher.
118
+ - The native QGIS run retains eight successful controls, two GeoPackages, one
119
+ raster, two portable projects and its synthetic capture/bundle.
120
+ - Each recipient receives a PDF and ZIP. Exact declared ZIP membership, member
121
+ hashes, PDF bytes/receipts, readable pages, recipient-specific text and retained
122
+ original inputs are checked. Repeated composition refuses overwrite.
123
+ - Selected packet bytes extracted from each ZIP are rechecked and reopened in
124
+ QGIS. The observed engine uses only the selected readonly packet, network none,
125
+ and its exact CID is absent afterward. Private verifier teardown and Web
126
+ drain/EOF/session-status confirm resource release.
127
+
128
+ Attempts 01/02 are retained: the acceptance driver initially inherited the host
129
+ test `PYTHONPATH` in its wheel-install/session-status subprocesses. The driver now
130
+ scrubs that environment, as it already did for the MCP launch. These were test
131
+ driver failures, not successful installed acceptance or changes to production
132
+ transport. The complete attempt 03 passes with the same Web package/runtime.
133
+
134
+ Host suite: **731 discovered, 703 passed, 28 explicit optional skips**.
135
+ `distribution-check`, `workflow-check`, `wheel-check`, `gem-check`, `mcp-check`
136
+ and the full `mcp-smoke` pass. `docs-build` also passes. Docker Make checks use issue-owned development
137
+ names (`unaltraweb:issue109-073`, `unaltraweb-mcp:issue109-073` and
138
+ `unaltraweb-manual-pdf:issue109-073`), not published aliases. Gem checks execute
139
+ inside that prepared Web image with network disabled.
140
+ The wheel gate additionally checks descriptor/BOM byte equality and absence of
141
+ private QGIS package roots. At this preparation checkpoint, exact-head review/CI
142
+ and publication were still pending; the completed delivery is recorded above.
143
+
144
+ ## Publication contract and remaining adoption
145
+
146
+ Use the normal reviewed-source image/package workflows and receipt-only release
147
+ commit. Reverify exact downloaded Web artifacts and the same descriptor against
148
+ the final candidates; retain the public controller/PDF archives separately from
149
+ the private QGIS dependency. Do not publish the private intake directory.
150
+
151
+ Final immutable Web/package/descriptor/receipt/image references were returned in
152
+ [gaContExt #38](https://github.com/dosquartsdedocs/gacontext/issues/38#issuecomment-6304912982).
153
+ The hub owns new preparation, compatibility curation and any
154
+ explicit consumer CAS selection/reload. Local acceptance, verified publication
155
+ and actual consumer adoption are distinct states. No teaching approval, scientific
156
+ manual recomputation, W1/SDK expansion or automatic consumer migration is claimed.
@@ -0,0 +1,140 @@
1
+ # Scaffold correction #115 / #118 — 0.7.4
2
+
3
+ This owner unit starts from published 0.7.3's post-release `main`
4
+ `2f9a8bdbc84a2ce5f5d10617174d36bcbde63f95`. The separate experimental #116 WIP
5
+ was checked against its retained source inventory and preserved without source
6
+ rewrites in **`6a8cd85ff75c8ad41dc67f8fb1c3c5a8f8919e53`**, branch
7
+ `feat/116-common-practice-sdk`. This scaffold correction does not contain that
8
+ checkpoint or close its QGIS/shared-runtime gates.
9
+
10
+ Implementation branch: `fix/118-reviewed-scaffold-resolution`. Clean preflight
11
+ was eligible after preservation. No worktree, stash, reset, manual checkout edit,
12
+ hub distribution edit or global cleanup is used.
13
+
14
+ ## Coherent independent tuple
15
+
16
+ The source target for package, gem artifact and controller/runtime is **0.7.4**.
17
+ The native Git adapter explicitly selects:
18
+
19
+ - Core: `9d97197dec5fc9346ab795191a3afd18884c27fb`.
20
+ - `consumer_integration.core_gem_version`: **0.7.3**, matching that actual source.
21
+ - Workflow: `3332e0b93933f12317e05f1ce8d38ce80046feab`.
22
+ - PDF 0.7.1: `ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:1bb3f2dafd741e96c28639ec1cc8ccaeb81cbaa73e649f787c0b4ef59997bd4b`.
23
+ - Classic QGIS 0.6.1 and all other independent worker/companion pins are preserved.
24
+
25
+ The generated native Gemfile/lock use the selected core's gem version, not the
26
+ wheel's release version. The controller-only `consumer-core.json` declares that
27
+ version and binds it to the BOM's exact core SHA; `consumer_advisory.py` projects
28
+ it into the public target as `core_gem_version`. The shared retained-document
29
+ checker module **and schema** remain byte-identical to the core and PDF worker.
30
+ Source validation reads the immutable Git commit's
31
+ contract and rejects a mismatch. Doctor/update comparisons use independent
32
+ component targets, so a coherent 0.7.4 MCP / 0.7.3 Git core is not perpetually
33
+ reported as out of date. Docker's existing generated Bundler state still loads
34
+ the core bundled in its selected image; author Gemfile/lock bytes stay intact.
35
+
36
+ ## Reviewed resolutions
37
+
38
+ The public `scaffold_sync` tool and CLI accept an optional `review` object.
39
+ Conflicted plans expose `review_inputs` and `resolution_options`, with exact
40
+ baseline, current, package and candidate-result hashes and UTF-8 review text.
41
+ The baseline is hash-only: these fields do not pretend to recover old source bytes.
42
+
43
+ Supported conservative decisions:
44
+
45
+ | Path | Mode | Preserved behavior |
46
+ | --- | --- | --- |
47
+ | `.gitignore` | `keep` | Keep the entire current byte sequence and inode. |
48
+ | `.gitignore` | `prepend-package` | Put package rules before the entire unmodified local sequence; local order and negation precedence remain last. |
49
+ | `.github/workflows/source-checks.yml` | `pins-only` | Replace only the two package/image env scalars. |
50
+ | `.github/workflows/deploy.yml` | `pins-only` | Replace only reusable-workflow, PDF-image and Vega-revision scalars. |
51
+
52
+ Workflow changes preserve every non-pin author value and all bytes outside the
53
+ pin scalars. Required controls and ordered steps must remain; extra independent
54
+ jobs/steps are preserved. Altered trigger/permission/concurrency controls, required
55
+ job execution modifiers, aliases, ambiguous keys, unsupported structures and
56
+ unsafe paths stay blocked. There is no arbitrary replacement-content or force API.
57
+
58
+ The existing staged-write, final CAS, no-clobber installation, manifest-last commit
59
+ and rollback implementation performs the writes. A concurrent author edit is
60
+ preserved with its original recovery backup when rollback cannot safely restore
61
+ that path. The next baseline retains the actual package hash, not a counterfeit
62
+ hash of a merged file. `reviewed_resolutions` records each decision and its hashes;
63
+ subsequent plans honestly show `preserved` / `current_customized` and detect later
64
+ upstream conflicts again.
65
+
66
+ ## Public migration sequence
67
+
68
+ For each idle consumer, preserve its current work and use the normal project
69
+ admission/reservation flow. After the coordinator prepares the published package:
70
+
71
+ 1. Obtain a fresh `site_context` and `scaffold_sync(dry_run=true)` plan. Never
72
+ reuse the old 0.7.3 plans or manually modify `.unaltraweb/scaffold.json`.
73
+ 2. Inspect each `review_inputs` row and the full proposed `resolution_options`.
74
+ For #118's broad `/dist/` and QGIS exclusions, `keep` preserves exact local
75
+ bytes; `prepend-package` is available if the additional package rules are
76
+ desired with local priority. Do not narrow the existing rules.
77
+ 3. Build a review containing the selected option's `path`, `mode`, all four hash
78
+ fields (omit its display `content`) and a concise human-reviewed `reason`:
79
+
80
+ ```json
81
+ {
82
+ "schema_version": 1,
83
+ "kind": "unaltraweb-scaffold-review",
84
+ "base_plan_sha256": "<fresh unresolved plan hash>",
85
+ "files": [
86
+ {
87
+ "path": ".gitignore",
88
+ "mode": "keep",
89
+ "baseline_sha256": "<from option>",
90
+ "local_sha256": "<from option>",
91
+ "payload_sha256": "<from option>",
92
+ "result_sha256": "<from option>",
93
+ "reason": "Preserve broad dist and four QGIS state exclusions"
94
+ }
95
+ ]
96
+ }
97
+ ```
98
+
99
+ Include reviewed `pins-only` entries for the source workflow and, where
100
+ conflicted, deployment workflow. A missing baseline hash is the empty string
101
+ only when that exact new-managed-file option says so.
102
+ 4. Call `scaffold_sync(dry_run=true, review=...)`. All conflicts must be resolved;
103
+ review the new `resolved`, `preserved`, target tuple and **resolved** plan hash.
104
+ 5. Apply the same review with `dry_run=false`, `confirm_sync=true` and that hash
105
+ as `expected_plan_sha256`. It is mandatory for reviewed resolutions. Changes
106
+ to local bytes, config, baseline, payload, decisions or project invalidate it.
107
+ 6. Inspect the next `site_context`/plan and run `site_check`. A valid preserved
108
+ customization remains visible; it must not be reported as pristine upstream.
109
+ Build/review through the consumer's native commands before its own publication.
110
+
111
+ CLI equivalent: `mcp scaffold-sync --review-json JSON` for the resolved dry-run,
112
+ then the same argument plus `--apply --confirm-sync --expected-plan-sha256 HASH`.
113
+ Git commits and manual publication remain separately coordinated owner actions.
114
+
115
+ ## Acceptance record
116
+
117
+ `scripts/test_scaffold_release.py` uses actual installed wheels and synthetic
118
+ consumers. The old creator is the downloaded published 0.5.0 wheel; baseline
119
+ files are never hand-written. Local ignore rules and workflow guards are then
120
+ added as author customizations. The candidate's CLI prepares the reviewed plan,
121
+ its real installed MCP applies it, and the following state is
122
+ `current_customized` with no repeated update. A stale review is refused.
123
+
124
+ `tmp/scaffold-118/acceptance-02/acceptance.json` records actual network Git fetch,
125
+ frozen Bundler resolution and consumption of **gem0.7.3 at core9d97197…**. Jekyll
126
+ build succeeds using the same explicit core/site config combination as the
127
+ generated Makefile. Gemfile, lock, ignore and manifest bytes remain unchanged by
128
+ Bundler. The first test used a bare Jekyll invocation without the core config;
129
+ its failed build log remains in `acceptance-01`, separately from the already
130
+ successful Git/gem resolution it observed.
131
+
132
+ The implementation tests also cover real ignore negations, all-path conflicts,
133
+ required workflow guards, stale input/result/decision hashes, cross-project and
134
+ unsafe-path refusal, symlinks, rollback and concurrent-edit recovery. Wheel tests
135
+ compare the complete top-level module inventory against source, excluding stale
136
+ build-cache modules and the separate #116 checkpoint.
137
+
138
+ Publication receipts, verified immutable images and final cold-download evidence
139
+ will be added after their actual gates complete. Source preparation or a passing
140
+ local acceptance is not a claim of release or manual activation.
@@ -0,0 +1,130 @@
1
+ """Opt-in installed-package scaffold migration and real Git/Bundler acceptance.
2
+
3
+ Uses synthetic consumers only. Old/new interpreters and an already-prepared Ruby
4
+ image are explicit; all evidence is create-only. Native Git/gem fetching during
5
+ the Bundler check is explicit, not part of normal site builds or scaffold plans.
6
+ """
7
+ from __future__ import annotations
8
+ import argparse
9
+ import asyncio
10
+ import hashlib
11
+ import json
12
+ import os
13
+ from pathlib import Path
14
+ import subprocess
15
+
16
+
17
+ def sha(path):
18
+ return hashlib.sha256(path.read_bytes()).hexdigest()
19
+
20
+
21
+ def save(path, value):
22
+ with path.open("x") as stream:
23
+ json.dump(value, stream, sort_keys=True, indent=2)
24
+ stream.write("\n")
25
+
26
+
27
+ def execute(command, *, env=None, timeout=180, expected=0):
28
+ result = subprocess.run(command, capture_output=True, text=True, env=env, timeout=timeout)
29
+ if expected is not None and result.returncode != expected:
30
+ raise RuntimeError(f"Command failed ({result.returncode}): {command}\n{result.stdout[-8000:]}\n{result.stderr[-8000:]}")
31
+ return result
32
+
33
+
34
+ def cli(python, project, *arguments, expected=0):
35
+ result = execute([str(python), "-I", "-B", "-m", "unaltraweb_mcp.cli", "--project", str(project), *arguments], expected=expected)
36
+ return json.loads(result.stdout)
37
+
38
+
39
+ async def mcp_roundtrip(python, project, factory, review, plan_hash):
40
+ from mcp import ClientSession, StdioServerParameters
41
+ from mcp.client.stdio import stdio_client
42
+ def payload(result):
43
+ return result.structuredContent or json.loads("\n".join(row.text for row in result.content if hasattr(row, "text")))
44
+ params = StdioServerParameters(command=str(python), args=["-I", "-B", "-m", "unaltraweb_mcp.cli", "--project", str(project), "mcp", "serve"],
45
+ env={"UNALTRAWEB_FACTORY_DIR": str(factory), "HOME": str(project), "PATH": os.environ["PATH"]})
46
+ async with stdio_client(params) as (incoming, outgoing):
47
+ async with ClientSession(incoming, outgoing) as client:
48
+ await client.initialize()
49
+ identity = payload(await client.call_tool("runtime_identity", {}))
50
+ assert identity["package"]["mode"] == "installed" and not identity["package"]["drift"]
51
+ result = payload(await client.call_tool("scaffold_sync", {"review": review, "dry_run": False, "confirm_sync": True, "expected_plan_sha256": plan_hash}))
52
+ assert result["ok"] and result["applied"], result
53
+ following = payload(await client.call_tool("site_context", {}))["update_status"]
54
+ assert following["state"] == "current_customized" and not following["update_available"], following
55
+ await client.call_tool("runtime_drain", {"confirm": True})
56
+ return {"identity": identity, "applied": result, "following": following}
57
+
58
+
59
+ def main():
60
+ parser = argparse.ArgumentParser(description=__doc__)
61
+ for name in ("old-python", "new-python", "output", "factory"):
62
+ parser.add_argument("--" + name, type=Path, required=True)
63
+ parser.add_argument("--runtime-image", required=True)
64
+ args = parser.parse_args()
65
+ root = args.output.resolve()
66
+ assert root == args.output and root.is_relative_to(args.factory / "tmp") and root.parent.is_dir()
67
+ root.mkdir(mode=0o700)
68
+ project, fresh = root / "upgrade", root / "fresh"
69
+ for python, path in ((args.old_python, project), (args.new_python, fresh)):
70
+ assert cli(python, path, "new-web", "--site-profile", "unaltremanual")["ok"]
71
+ original_baseline = sha(project / ".unaltraweb/scaffold.json")
72
+ ignore = project / ".gitignore"
73
+ ignore.write_bytes(ignore.read_bytes() + b"\n/dist/\n/.unaltracaptura-qgis/jobs/\n/.unaltracaptura-qgis/probes/\n/.unaltracaptura-qgis/render-locks/\n/.unaltracaptura-qgis/runtime/\n/notes/*\n!/notes/public/\n")
74
+ for name in ("source-checks.yml", "deploy.yml"):
75
+ path = project / ".github/workflows" / name
76
+ path.parent.mkdir(parents=True, exist_ok=True)
77
+ # A local workflow with the official controls plus an author guard and
78
+ # previous pins; its older package baseline remains untouched.
79
+ current = (fresh / ".github/workflows" / name).read_text()
80
+ current = current.replace("unaltraweb-mcp==0.7.4", "unaltraweb-mcp==0.7.3")
81
+ current += "\n author-guard:\n runs-on: ubuntu-latest\n steps:\n - run: test -f _config.yml\n"
82
+ path.write_text(current)
83
+ assert sha(project / ".unaltraweb/scaffold.json") == original_baseline
84
+ ignored_before = ignore.read_bytes()
85
+ plan = cli(args.new_python, project, "mcp", "scaffold-sync", expected=None)
86
+ save(root / "initial-plan.json", plan)
87
+ assert not plan["ok"] and {row["path"] for row in plan["conflicts"]} == {".gitignore", ".github/workflows/deploy.yml", ".github/workflows/source-checks.yml"}, plan
88
+ modes = {".gitignore": "keep", ".github/workflows/deploy.yml": "pins-only", ".github/workflows/source-checks.yml": "pins-only"}
89
+ decisions = [{key: value for key, value in row.items() if key != "content"} | {"reason": "Preserve synthetic author rules and controls; accept exact package pins"}
90
+ for row in plan["resolution_options"] if modes.get(row["path"]) == row["mode"]]
91
+ assert len(decisions) == 3
92
+ review = {"schema_version": 1, "kind": "unaltraweb-scaffold-review", "base_plan_sha256": plan["plan_sha256"], "files": decisions}
93
+ save(root / "review.json", review)
94
+ resolved = cli(args.new_python, project, "mcp", "scaffold-sync", "--review-json", json.dumps(review))
95
+ save(root / "resolved-plan.json", resolved)
96
+ assert resolved["ok"] and not resolved["applied"]
97
+ applied = asyncio.run(mcp_roundtrip(args.new_python, project, args.factory, review, resolved["plan_sha256"]))
98
+ save(root / "installed-mcp.json", applied)
99
+ assert ignore.read_bytes() == ignored_before
100
+ for name in ("source-checks.yml", "deploy.yml"):
101
+ assert "author-guard:" in (project / ".github/workflows" / name).read_text()
102
+ stale = execute([str(args.new_python), "-I", "-B", "-m", "unaltraweb_mcp.cli", "--project", str(project), "mcp", "scaffold-sync",
103
+ "--review-json", json.dumps(review), "--apply", "--confirm-sync", "--expected-plan-sha256", resolved["plan_sha256"]], expected=None)
104
+ assert stale.returncode != 0
105
+ assert cli(args.new_python, fresh, "mcp", "site-context")["update_status"]["state"] == "current"
106
+ snapshots = {name: sha(project / name) for name in ("Gemfile", "Gemfile.lock", ".gitignore", ".unaltraweb/scaffold.json")}
107
+ ruby = '''require "json"; require "unaltraweb/version"; require "open3"; s=Gem.loaded_specs.fetch("unaltraweb"); revision,status=Open3.capture2("git","-C",s.full_gem_path,"rev-parse","HEAD"); abort "missing git source" unless status.success?; puts JSON.generate({version: Unaltraweb::VERSION, gem_version: s.version.to_s, revision: revision.strip, path: s.full_gem_path})'''
108
+ command = ["docker", "run", "--rm", "--pull=never", "--network=bridge", "--cpus=2", "--memory=2g", "--pids-limit=256",
109
+ "--env", "HOME=/tmp", "--env", "BUNDLE_FROZEN=true", "--env", "BUNDLE_APP_CONFIG=/site/tmp/bundle-config",
110
+ "--label", "io.context.mcp-factory=unaltraweb", "--label", "io.context.mcp-role=scaffold-118-bundler",
111
+ "--mount", "type=bind,source=" + str(project) + ",target=/site", "--workdir", "/site", "--entrypoint", "bash", args.runtime_image,
112
+ "-lc", "bundle install && bundle exec ruby -e \"$1\" && core=\"$(bundle info --path unaltraweb)\" && bundle exec jekyll build --config \"$core/_config.yml,_config.yml\" --disable-disk-cache --trace", "acceptance", ruby]
113
+ built = execute(command, timeout=900, expected=None)
114
+ (root / "bundler.log").write_text(built.stdout + built.stderr)
115
+ assert built.returncode == 0, built.stderr[-8000:] + built.stdout[-8000:]
116
+ observed = next(json.loads(line) for line in built.stdout.splitlines() if line.startswith('{"version":'))
117
+ assert observed["version"] == observed["gem_version"] == resolved["target"]["core_gem_version"]
118
+ assert observed["revision"] == resolved["target"]["core_sha"]
119
+ assert all(sha(project / name) == expected for name, expected in snapshots.items())
120
+ assert (project / "_site/index.html").is_file()
121
+ record = {"ok": True, "synthetic_only": True, "native_bundler": observed, "target": resolved["target"],
122
+ "old_baseline_sha256": original_baseline, "initial_plan_sha256": plan["plan_sha256"],
123
+ "resolved_plan_sha256": resolved["plan_sha256"], "managed_bytes_unchanged_by_bundler": snapshots,
124
+ "following": applied["following"], "stale_review_refused": True}
125
+ save(root / "acceptance.json", record)
126
+ print(json.dumps(record, indent=2))
127
+
128
+
129
+ if __name__ == "__main__":
130
+ main()
@@ -61,6 +61,12 @@ def main() -> int:
61
61
  raise RuntimeError(f"Expected one wheel, found: {wheels}")
62
62
  with zipfile.ZipFile(wheels[0]) as archive:
63
63
  names = archive.namelist()
64
+ expected_modules = {path.name: path.read_bytes() for path in (ROOT / "src/unaltraweb_mcp").iterdir()
65
+ if path.is_file() and path.suffix in {".py", ".json"}}
66
+ installed_modules = {Path(name).name: archive.read(name) for name in names
67
+ if Path(name).parent.as_posix() == "unaltraweb_mcp" and Path(name).suffix in {".py", ".json"}}
68
+ if installed_modules != expected_modules:
69
+ raise RuntimeError("Wheel contains missing, stale or foreign package modules")
64
70
  launcher_prefix = f"{wheels[0].name.split('-')[0]}-{wheels[0].name.split('-')[1]}.data/data/share/unaltraweb-launcher/"
65
71
  launcher_files = {
66
72
  "Makefile": "packaging/launcher/Makefile",
@@ -76,6 +82,11 @@ def main() -> int:
76
82
  for installed_path, source_path in launcher_files.items():
77
83
  if archive.read(launcher_prefix + installed_path) != (ROOT / source_path).read_bytes():
78
84
  raise RuntimeError(f"Wheel launcher asset differs from source: {installed_path}")
85
+ for name in ("component-contract.json", "practice-verifier-runtime.json"):
86
+ if archive.read("unaltraweb_mcp/" + name) != (ROOT / "src/unaltraweb_mcp" / name).read_bytes():
87
+ raise RuntimeError(f"Wheel dependency declaration differs from source: {name}")
88
+ if any(name.startswith(("veure_qgis_mcp/", "unaltracaptura_annotations/")) for name in names):
89
+ raise RuntimeError("Private QGIS implementation leaked into the public wheel")
79
90
  forbidden_roots = {"docs", "scripts", "_layouts", "_includes", "_sass"}
80
91
  leaked = []
81
92
  for name in names:
@@ -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:6aa20cff86c3891a876e37ba0548fa36f3c5633c9f22ba672e9f50123d677cf6}"
18
+ image="${UNALTRAWEB_MCP_IMAGE:-ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:8183e7117f5902fc0ad4d930b757d874b2da1f93d5ef4db102ae4c1b03e357a3}"
19
19
  project="${MCP_CONSUMER_WORKSPACE:-${UNALTRAWEB_PROJECT:-}}"
20
20
  operation=serve
21
21
  expected_image="${UNALTRAWEB_EXPECTED_IMAGE_ID:-}"
@@ -105,6 +105,17 @@ def selected_deployment_errors(contract: dict[str, Any], workflow: dict[str, Any
105
105
  return errors
106
106
 
107
107
 
108
+ def selected_core_gem_errors(contract: dict[str, Any], core_contract: dict[str, Any]) -> list[str]:
109
+ from unaltraweb_mcp.consumer_advisory import consumer_core_policy
110
+ policy = consumer_core_policy()
111
+ expected = policy["gem_version"]
112
+ actual = core_contract.get("release", {}).get("version")
113
+ declared = core_contract.get("components", {}).get("gem", {}).get("version")
114
+ if policy["core_sha"] != contract["consumer_integration"]["core_sha"] or expected != actual or expected != declared:
115
+ return ["selected immutable core source's gem version differs from consumer_integration.core_gem_version"]
116
+ return []
117
+
118
+
108
119
  def validate(root: Path = ROOT) -> list[str]:
109
120
  errors: list[str] = []
110
121
  contract = distribution_contract()
@@ -173,6 +184,13 @@ def validate(root: Path = ROOT) -> list[str]:
173
184
  )
174
185
  if core_ancestor.returncode != 0:
175
186
  errors.append("consumer integration core SHA must be an ancestor of the current source")
187
+ core_record = subprocess.run(["git", "show", f"{core_sha}:src/unaltraweb_mcp/component-contract.json"],
188
+ cwd=root, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
189
+ try:
190
+ selected_core = json.loads(core_record.stdout) if core_record.returncode == 0 else {}
191
+ errors.extend(selected_core_gem_errors(contract, selected_core))
192
+ except (ValueError, TypeError, AttributeError):
193
+ errors.append("selected immutable core has no readable gem version contract")
176
194
  pinned_workflow = subprocess.run(
177
195
  ["git", "show", f"{workflow_sha}:.github/workflows/site-deploy.yml"],
178
196
  cwd=root,
@@ -2,13 +2,13 @@
2
2
  "$schema": "component-contract.schema.json",
3
3
  "schema_version": 1,
4
4
  "release": {
5
- "version": "0.7.2",
6
- "tag": "v0.7.2"
5
+ "version": "0.7.4",
6
+ "tag": "v0.7.4"
7
7
  },
8
8
  "consumer_integration": {
9
9
  "schema_version": 1,
10
10
  "core_repository": "https://github.com/dosquartsdedocs/unaltraweb.git",
11
- "core_sha": "3332e0b93933f12317e05f1ce8d38ce80046feab",
11
+ "core_sha": "9d97197dec5fc9346ab795191a3afd18884c27fb",
12
12
  "site_deploy_workflow": "dosquartsdedocs/unaltraweb/.github/workflows/site-deploy.yml",
13
13
  "site_deploy_workflow_sha": "3332e0b93933f12317e05f1ce8d38ce80046feab",
14
14
  "manual_pdf_image": "ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf@sha256:1bb3f2dafd741e96c28639ec1cc8ccaeb81cbaa73e649f787c0b4ef59997bd4b",
@@ -62,10 +62,10 @@
62
62
  "gem": {
63
63
  "kind": "gem",
64
64
  "name": "unaltraweb",
65
- "version": "0.7.2",
66
- "release": "v0.7.2",
65
+ "version": "0.7.4",
66
+ "release": "v0.7.4",
67
67
  "release_status": "ready",
68
- "reference": "unaltraweb (= 0.7.2)",
68
+ "reference": "unaltraweb (= 0.7.4)",
69
69
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
70
70
  "included_in_wheel": false,
71
71
  "features": ["jekyll-core", "site-build"]
@@ -73,10 +73,10 @@
73
73
  "wheel": {
74
74
  "kind": "python-wheel",
75
75
  "name": "unaltraweb-mcp",
76
- "version": "0.7.2",
77
- "release": "v0.7.2",
76
+ "version": "0.7.4",
77
+ "release": "v0.7.4",
78
78
  "release_status": "ready",
79
- "reference": "unaltraweb-mcp==0.7.2",
79
+ "reference": "unaltraweb-mcp==0.7.4",
80
80
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
81
81
  "included_in_wheel": true,
82
82
  "features": ["calibre-import", "doctor", "new-web", "offline-inspection", "mcp-control-plane", "source-ci"]
@@ -84,10 +84,10 @@
84
84
  "runtime": {
85
85
  "kind": "container",
86
86
  "name": "unaltraweb runtime",
87
- "version": "0.7.2",
88
- "release": "v0.7.2",
87
+ "version": "0.7.4",
88
+ "release": "v0.7.4",
89
89
  "release_status": "ready",
90
- "reference": "ghcr.io/dosquartsdedocs/unaltraweb:0.7.2",
90
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb:0.7.4",
91
91
  "image_repository": "ghcr.io/dosquartsdedocs/unaltraweb",
92
92
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
93
93
  "included_in_wheel": false,
@@ -96,10 +96,10 @@
96
96
  "mcp": {
97
97
  "kind": "container",
98
98
  "name": "unaltraweb MCP runtime",
99
- "version": "0.7.2",
100
- "release": "v0.7.2",
99
+ "version": "0.7.4",
100
+ "release": "v0.7.4",
101
101
  "release_status": "ready",
102
- "reference": "ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.2",
102
+ "reference": "ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.7.4",
103
103
  "image_repository": "ghcr.io/dosquartsdedocs/unaltraweb-mcp",
104
104
  "repository": "https://github.com/dosquartsdedocs/unaltraweb",
105
105
  "included_in_wheel": false,
@@ -156,10 +156,10 @@
156
156
  "qgis_practice_verifier": {
157
157
  "kind": "companion",
158
158
  "name": "unaltracaptura-qgis",
159
- "version": "0.6.0",
160
- "release": "v0.6.0",
159
+ "version": "0.6.1",
160
+ "release": "v0.6.1",
161
161
  "release_status": "released",
162
- "reference": "https://github.com/dosquartsdedocs/unaltracaptura-qgis.git@v0.6.0",
162
+ "reference": "https://github.com/dosquartsdedocs/unaltracaptura-qgis.git@v0.6.1",
163
163
  "repository": "https://github.com/dosquartsdedocs/unaltracaptura-qgis",
164
164
  "included_in_wheel": false,
165
165
  "features": ["qgis-practice-v1", "qgis-practice-v2", "private-prepared-runtime"]
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.2
4
+ version: 0.7.4
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-12 00:00:00.000000000 Z
11
+ date: 2026-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: classifier-reborn
@@ -817,8 +817,10 @@ files:
817
817
  - docs/agents/practice-pdf-installable-98.md
818
818
  - docs/agents/practice-runtime-archives-98.md
819
819
  - docs/agents/private-practice-verifier-98.md
820
+ - docs/agents/qgis-0.6.1-adoption-109.md
820
821
  - docs/agents/quarto-computation-adoption.md
821
822
  - docs/agents/retained-letter-import.md
823
+ - docs/agents/scaffold-closeout-118.md
822
824
  - docs/agents/source-ci-98.md
823
825
  - docs/agents/visual-companions-0.4.0.md
824
826
  - docs/assets/img/caption-credits-demo.svg
@@ -857,6 +859,7 @@ files:
857
859
  - scripts/prepare_practice_editions_candidate.py
858
860
  - scripts/test_gem_build.py
859
861
  - scripts/test_reproducible_jekyll_build.py
862
+ - scripts/test_scaffold_release.py
860
863
  - scripts/test_wheel_install.py
861
864
  - scripts/unaltraweb-docker-mount.sh
862
865
  - scripts/unaltraweb-mcp-bootstrap.sh