unaltraweb 0.7.4 → 0.8.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.
@@ -0,0 +1,277 @@
1
+ # #121 — review after real-manual pilots, 2026-11-04
2
+
3
+ ## Findings and implementation order
4
+
5
+ 1. **P1, producer defect:** declared computation inputs are incorrectly subjected
6
+ to the public-content root allowlist. This is the first reported TIGIT blocker
7
+ and is reproduced against the published 0.8.0 image, independently of missing
8
+ data, stale output, receiver behavior or an old client connection.
9
+ 2. **P2, producer defect:** HTML image metadata containing inline code retains
10
+ internal protection tokens in the manifest. This was found by the review's
11
+ synthetic component probe; it is not claimed as a reported TIGIT error.
12
+ 3. **Coordinated compatibility extension:** SVG embedded rasters are refused by
13
+ both released Web 0.8.0 and Itemarium 0.6.2. Widening Web alone cannot deliver
14
+ a consumable package. Agree a bounded profile/version and update both owners.
15
+ 4. **Producer provenance extension:** recognizable QGIS capture provenance has
16
+ no context exporter adapter. This is distinct from SVG raster compatibility;
17
+ even a standalone vector SVG can hit this producer gate.
18
+
19
+ The immediate useful Web increment is **1 + 2**, with the unchanged v1 transport
20
+ and an explicit new release/adoption. Then the TIGIT owner reruns the selected
21
+ chapter. There is no evidence yet that general Liquid execution or QGIS/raster
22
+ support is necessary for that particular chapter to pass its next gate.
23
+
24
+ This is a review with executable reproductions, not a runtime repair or a new
25
+ release. Production modules, schema and pins remain unchanged. The experimental
26
+ #116 checkpoint remains `6a8cd85ff75c8ad41dc67f8fb1c3c5a8f8919e53` on
27
+ `feat/116-common-practice-sdk`; none of it is used here.
28
+
29
+ ## State: publication, admission and the actual caller
30
+
31
+ - Web 0.8.0 is published; artifact source
32
+ `54afe7588c36e959a7eb75d5f52763a7456108d7`, controller config ID
33
+ `sha256:e0502369c85c59f9e512fbd9fdb17dbc128845d057a1423375425e68ce2e79a2`,
34
+ OCI digest `sha256:8b41abacad9ca2894755db7f3587a6b47c8fa8f536d88a151bdfc4ae53ba7f08`.
35
+ - [gaContExt PR55](https://github.com/dosquartsdedocs/gacontext/pull/55) is integrated
36
+ at `ccbe1610f975faee913044c47b567cfe5b856cc0`. Configured controls are
37
+ `c6b5ab73abc399d47489c199e9b91628254b84868674712a21acf0db42e9d768`.
38
+ Web 0.8.0 and Itemarium 0.6.2 are prepared/enrolled. Managed export/import,
39
+ version preservation and backup/reopening pass. See the
40
+ [hub return](https://github.com/dosquartsdedocs/gacontext/issues/54#issuecomment-6615276920).
41
+ - The final fresh readonly TIGIT OpenCode status confirms **revision 5 / Web
42
+ 0.8.0**, with matching configuration, deployment `272e7dce…` and the enrolled
43
+ controller above. Its older live connection `4ac20e8829224276a8765beefc71b559`
44
+ still loads **0.7.4**. The initial observation in this review returned the
45
+ preceding revision-4 state; it is superseded by this reobservation and the
46
+ [TIGIT #27 return](https://github.com/geourv/tigit/issues/27#issuecomment-6625078407).
47
+ - TIGIT's owner explicitly activated the new point and invoked a bounded managed
48
+ connection with loaded/current 0.8.0, no drift, correct binding and 65 tools.
49
+ Its complete-Catalan export hits the same private-input error, creates no
50
+ package/receipt, then drains/exits and leaves its exact controller absent.
51
+ Restarting the older connection does not repair this confirmed 0.8.0 defect.
52
+ - TIGIT's local `_config.yml` already contains `unaltraweb.manual.id: tigit`.
53
+ The old missing-ID diagnosis is obsolete for that inspected working copy.
54
+ - Itemarium's 2026-11-04 report observes native **0.6.2 / 63 tools**, unchanged
55
+ frozen bytes, and a separate Web 0.7.4 connection bound to Itemarium. Its actual
56
+ real-manual CLI probe explicitly uses the published 0.8.0 image in a readonly,
57
+ network-disabled mount. It creates no real manual package.
58
+
59
+ Owner input: `itemarium/docs/handoffs/2026-11-04-manual-adoption-readiness.ca.md`,
60
+ SHA256 `1a9438e6c2f412200006f9769069e98fa42d76c101a3556b154dbc6ca6d4195c`;
61
+ retained pilot `tmp/manual-readiness-20261104/receipt.json`, SHA256
62
+ `551c372cfd0576d1ee71cbb2be0b6f614d4fc783ecc474c06c783822f20d24d2`.
63
+ These were inspected read-only while the receiver owner retained its working
64
+ changes. No teacher-bank contents were needed for this review.
65
+
66
+ ## P1 — separate check-only dependencies from transported public content
67
+
68
+ The owner reports identical exit-1 failures for the whole manual and
69
+ `--chapter manual-territorial-indicators`:
70
+
71
+ ```text
72
+ UW-MANUAL-CONTEXT
73
+ Resource is outside the public manual source roots:
74
+ _practices/tigit-projecte-territorial/data/processed/tarragones-boundaries-icgc-20260120.gpkg
75
+ ```
76
+
77
+ The declaration is present in
78
+ `assets/quarto/cartographic-language/minimum-mapping-unit-tarragones.qmd`, lines
79
+ 13–19. It is a computation input; the declared published output is an SVG under
80
+ `assets/img/`. The call chain is
81
+ `Sources._computations → dependency → Snapshot.public`, at
82
+ [`manual_context_sources.py:40–47`](https://github.com/dosquartsdedocs/unaltraweb/blob/v0.8.0/src/unaltraweb_mcp/manual_context_sources.py#L40-L47).
83
+ `Snapshot.public` is appropriate for content entering the transport but rejects
84
+ this check-only dependency before native freshness verification.
85
+ The TIGIT owner also confirms an existing regular GPKG of **598016 bytes**, below
86
+ the exporter's current 10 MiB per-file reader limit. The observed blocker is its
87
+ root/role policy, not that size limit.
88
+
89
+ Published-image reproductions:
90
+
91
+ - `public-input`: a synthetic declared input under `assets/data/` passes the
92
+ native computation status and actual export. The input itself is absent from
93
+ the transport; only the effective section and SVG are declared.
94
+ - `private-input`: the same opaque bytes and valid synthetic native record under
95
+ `_practices/fixture/data/` pass native `status` (`current_count:1`, `ok:true`),
96
+ then fail in the exporter with the reported root error. The file exists; no
97
+ missing-file or GIS-format failure is inferred. No computation is executed.
98
+ - `private-input-other-chapter`: the same refusal occurs when selecting a chapter
99
+ that does not reference the computation. This confirms the existing global
100
+ completeness gate, rather than an ineffective chapter selector.
101
+ - `changed-public-input` gives `source_or_environment_changed`; `missing-figure`
102
+ gives `Missing editorial input`. These are distinct local-source conditions.
103
+ - `private-image` is correctly refused. Adding `_practices` indiscriminately to
104
+ `public_roots` would weaken this required transport boundary.
105
+
106
+ ### Concrete repair and tests
107
+
108
+ Introduce a separate bounded dependency-read/snapshot path for **explicit native
109
+ input declarations**. Keep public-source/image selection on `Snapshot.public`.
110
+ Use the existing descriptor-relative reader, literal project-relative validation,
111
+ no-follow rules and before/after rechecks. Permit verification of the declared
112
+ private input without discovering/copying an entire private repository or sending
113
+ its content. Keep native global completeness and fingerprint checks intact.
114
+
115
+ The two roles must remain separate throughout the snapshot, input fingerprint,
116
+ resolution evidence and final transport inventory. Required regression cases:
117
+
118
+ 1. An unchanged declared `_practices/...` input passes native checking/export;
119
+ only selected sections and effective figures appear in the tar and `files`.
120
+ 2. Sentinel private data, private paths and executable source bytes do not leak
121
+ into transported Markdown/figures/manifest. A private path may remain in the
122
+ producer's external retained check receipt, not the content package.
123
+ 3. Changed/missing inputs, modified outputs and stale records still fail;
124
+ chapter selection cannot bypass the global check.
125
+ 4. Traversal, symlinks, undeclared/private image or include references and source
126
+ changes during export still fail before a sealed delivery.
127
+ 5. Dependency byte budgets remain explicit and bounded. If a real declared input
128
+ exceeds the current reader budget, assess a bounded streaming snapshot/hash
129
+ path separately; do not silently increase the image/text transport limits.
130
+
131
+ No v1 schema extension is needed for this role correction. Moving the GPKG into
132
+ public assets, removing its declaration, skipping global checks or hand-authoring
133
+ a package in Itemarium are not a verification of the repair.
134
+
135
+ ## P2 — restore HTML figure metadata before registration
136
+
137
+ Input used in `html-caption-code`:
138
+
139
+ ```html
140
+ <img src="assets/img/plain.svg" alt="Alt `code`" title="Caption `literal`">
141
+ ```
142
+
143
+ The real published exporter succeeds but records:
144
+
145
+ ```json
146
+ {"alt":"Alt UNALTRAWEBEXPORTPROTECTED0TOKEN",
147
+ "caption":"Caption UNALTRAWEBEXPORTPROTECTED1TOKEN"}
148
+ ```
149
+
150
+ [`Projection.text`](https://github.com/dosquartsdedocs/unaltraweb/blob/v0.8.0/src/unaltraweb_mcp/manual_context.py#L261-L326)
151
+ restores protected Markdown-image attributes before `figure()`, but
152
+ [`html_images`](https://github.com/dosquartsdedocs/unaltraweb/blob/v0.8.0/src/unaltraweb_mcp/manual_context.py#L328-L351)
153
+ registers HTML attributes while they still contain placeholders. The final text
154
+ restoration does not repair the previously registered manifest or figure ID.
155
+
156
+ The actual produced package SHA is
157
+ `53d065605af60cd90f73553b3c7004a52c6fa6e74ec4a0f88336f879f161296a`.
158
+ Itemarium's independent package checker accepts it: byte integrity is correct,
159
+ but `caption_preserved:false` exposes the semantic error. This is a producer
160
+ fidelity defect, not a malformed source or a receiver checksum failure.
161
+
162
+ Restore `alt`, caption/title and credits before calculating the registration ID
163
+ and storing metadata, or replace placeholder-based attribute handling with a
164
+ token-aware path. Add assertions for exact HTML/Markdown metadata parity, quoted
165
+ and escaped attributes, inline code in credits, absence of internal markers and
166
+ stable figure identity when unrelated code appears earlier in the text.
167
+
168
+ ## Components and Liquid: supported subset versus missing functionality
169
+
170
+ The `components` case combines a literal include, definitions, a localized
171
+ callout, a citation, table, subfigures and `site.baseurl`. Its actual archive is
172
+ accepted independently by Itemarium. These are the same principal source forms
173
+ observed in TIGIT chapter 2; this does not prove the complete real chapter exports.
174
+
175
+ `{{ page.title }}` and a parameterized include are refused with the documented
176
+ Liquid/include diagnostics. No real pilot return inspected here reaches one of
177
+ those errors. They are explicit unsupported producer forms, not evidence that
178
+ all Liquid/components fail or that an old client explains the private-input error.
179
+
180
+ If the subsequent pilot needs another form, record its exact source fragment and
181
+ add a deliberately bounded resolver case with source/resource closure and literal
182
+ code protection. Do not replace export with unrestricted Jekyll/Liquid execution.
183
+ Diagnostics should identify the rejected form and source location distinctly
184
+ from a missing include or a stale resource.
185
+
186
+ ## SVG with raster: coordinate producer and receiver policy
187
+
188
+ `embedded-raster` contains a valid, small PNG embedded as
189
+ `<image href="data:image/png;base64,...">` in a standalone SVG. Web rejects it at
190
+ `manual_context_media.validate_image`; Itemarium's existing `app.media.read_image`
191
+ independently rejects the **same image bytes**, before any package import.
192
+ The external-URL raster control is also refused. No alternative transport archive
193
+ is fabricated for these checks; they are image-member validator probes only.
194
+
195
+ Required coordinated work, if the pilot needs these effective figures:
196
+
197
+ - Agree the compatibility profile/version rather than silently widening v1 or
198
+ adding unrecognized manifest fields. The admitted Itemarium 0.6.2 point rejects
199
+ the current payload even if only Web's allowlist is changed.
200
+ - Permit only agreed raster MIME types, verified base64/decoded bytes, dimensions,
201
+ pixel/byte/element budgets and safe image decoding. Preserve XML/DTD/entity,
202
+ active-content and external-network/resource refusals.
203
+ - Preserve the selected edited SVG and bind the delivered effective bytes to new
204
+ resolution evidence. Never substitute the original screenshot or rasterize as
205
+ an implicit export side effect.
206
+ - Test valid embedded PNG/JPEG, oversized/malformed data, nested SVG data URLs,
207
+ external href/CSS and actual exported-package checking/import/backup in the new
208
+ receiver. New installed bytes need their own release/admission evidence.
209
+
210
+ ## QGIS provenance: a separate gate
211
+
212
+ `qgis-vector` has only safe vector geometry/text plus synthetic QGIS metadata:
213
+ Itemarium's image validator accepts the SVG, but Web refuses missing QGIS capture
214
+ provenance. Thus adding raster support alone does not solve this gate.
215
+
216
+ `qgis-untyped` supplies ordinary static vector bytes with a QGIS-related alt label.
217
+ It exports as `resolution.kind: static`. That is not proof of a fresh QGIS output:
218
+ the current byte-token/path heuristic is a refusal hint, not a provenance adapter.
219
+ Removing metadata to force static treatment is not an acceptable adoption route.
220
+
221
+ Implement an explicit mapping from a declared QGIS output to an independently
222
+ verified producer bundle/receipt, selected original/edited output and complete
223
+ required resource closure. Verify hashes, native producer/profile identity and
224
+ freshness; bind new evidence to the exact effective bytes. Reject missing/tampered
225
+ receipts, stale edits, incomplete resources and mismatched outputs. Exercise native
226
+ QGIS verification through an agreed existing interface; do not embed the private
227
+ QGIS implementation in Web or trust a caller's success boolean.
228
+
229
+ The schema already names `qgis-capture`, but no record dispatch in 0.8.0 produces
230
+ that verified kind. Pin/qualify the actual classic capture profile separately;
231
+ this review does not adopt the #116 shared-job checkpoint or a different QGIS
232
+ practice tuple. After provenance works, the effective SVG must still satisfy the
233
+ negotiated receiver image policy.
234
+
235
+ ## Reproduction and evidence
236
+
237
+ Versioned runner: `scripts/review_manual_context_pilots.py`. It requires the two
238
+ already-prepared published controller IDs (0.8.0 and 0.7.4), never pulls, and uses
239
+ network-disabled/read-only-root containers with no Docker socket and only new
240
+ synthetic fixture inputs. The 0.7.4 control rejects the unknown CLI command with
241
+ exit 2; this is distinct from the published 0.8.0 content error (exit 1).
242
+
243
+ ```bash
244
+ python scripts/review_manual_context_pilots.py \
245
+ --output /absolute/unaltraweb/tmp/context-pilot-review-new \
246
+ --receiver-python /absolute/prepared-python/bin/python \
247
+ --receiver-source /home/benizar/git/itemarium/tools/itemarium
248
+ ```
249
+
250
+ The receiver flags are paired and optional. The receiver source is read-only,
251
+ bytecode writes are disabled, and its before/after engine fingerprint is checked.
252
+ Only archives actually produced by the published exporter reach `check_package`.
253
+ There is no app/bank creation or question generation in this review.
254
+
255
+ Completed run: `tmp/manual-context-pilot-review-20261104-02/`:
256
+
257
+ - 16 producer scenarios, five actual archives independently accepted by the
258
+ receiver; expected refusals remain failures in the retained domain responses.
259
+ - Producer identity `sha256:a678d2b2649e3479d0049ca0ca8a500aba5bb3f0a59b070cd7aaf5c0c6b466d0`.
260
+ - `producer-review.json` SHA256
261
+ `3a33b4b844bbc6e41419f420146d45e96b963bede0f04ae1e690c1a09dc25d69`.
262
+ - `receiver-review.json` SHA256
263
+ `2c6944d9778e317dda5c0f6dfaf74cda5d7a339e7ad61dfb20f3012df071f521`.
264
+ - Receiver source checker: 0.6.2, engine SHA256
265
+ `1a8983100c4b0c72bac74912fdde7a4d8ad14ce9970e188f13aae611dbeee813`.
266
+ - Original fixture sources remain unchanged during export, and exact review
267
+ container absence is checked with a responsive Docker daemon.
268
+ - The initial `-01` attempt failed in the review harness's root-mounted script
269
+ path calculation before exporter execution. It is retained, corrected in the
270
+ harness and not misclassified as a product failure.
271
+ - Full existing suite: 763 cases, 736 passed, 27 skips; `git diff --check` passes.
272
+
273
+ No live consumer activation, real-manual export, publication or runtime/schema
274
+ patch is performed here. TIGIT owns its local sources/adoption and the next real
275
+ chapter export; Web owns the two identified producer repairs and coordinated
276
+ format/provenance extensions; Itemarium owns receiver changes and eventual
277
+ explicit import with bank preservation.
@@ -38,10 +38,11 @@ it to an image ID before execution. The source checkout's digest pin is separate
38
38
  it advances only after a new receipt exists. Explicit `--image` (or the console
39
39
  adapter's `UNALTRAWEB_MCP_IMAGE`) permits a reviewed immutable selection.
40
40
 
41
- The post-release checkout pin selects published 0.7.1 MCP digest
42
- `sha256:6aa20cff86c3891a876e37ba0548fa36f3c5633c9f22ba672e9f50123d677cf6`.
43
- The [0.7.1 delivery report](owner-closeout-93.md) records the consolidated deployment
44
- contract, exact hotfix migration and matching PDF verifier closure.
41
+ The post-release checkout pin selects published 0.8.0 MCP digest
42
+ `sha256:8b41abacad9ca2894755db7f3587a6b47c8fa8f536d88a151bdfc4ae53ba7f08`.
43
+ The [0.8.0 delivery report](manual-context-121.md) records the verified portable
44
+ manual exporter, public artifact tuple and independent Itemarium conformance.
45
+ The coherent core/gem tuple and reviewed scaffold migration from 0.7.4 remain.
45
46
  Existing processes keep their running image until clients reconnect. Site build
46
47
  defaults and customized Makefiles remain separate, explicitly reviewed selections.
47
48
 
@@ -89,6 +90,7 @@ baseline format nor runtime cleanup changes.
89
90
 
90
91
  | Resource | Description |
91
92
  | --- | --- |
93
+ | `web://manual-context-schema` | Portable manual context v1 schema, byte-identical to the reviewed Itemarium consumer contract. |
92
94
  | `web://practice-edition-schema` | Versioned Web recipient/edition configuration, separate from the producer-owned GIS descriptor. |
93
95
  | `web://practice-verifier-runtime` | Static private controller/package/profile identities and distinct release metadata; acquisition belongs to the hub. |
94
96
  | `web://runtime-identity` | Bounded identity of this serving process: startup/current code, instance/PID namespaces, binding, runtime selections and cooperative lifecycle. |
@@ -179,6 +181,7 @@ without a portable edition context; HTTPS and internal anchors remain intact.
179
181
 
180
182
  | Tool | Notes |
181
183
  | --- | --- |
184
+ | `manual_context_export` | Create-only export of the bound manual's selected language/chapter refs/exact section IDs; returns a retained tar.gz and real SHA256. No arbitrary root, renderer, publication or Itemarium runtime dependency. See [context export](../_documentation/en/47-manual-context.md). |
182
185
  | `manual_practice_compose` | One versioned consumer configuration selects GIS roots, two approved reading hashes and optional declared editable-SVG resources; delivers an independent PDF and ZIP per recipient with complete closure and create-only receipts. |
183
186
  | `runtime_identity` | Observe the actual serving instance, startup/current package evidence and selected/observed images; never prepare a runtime or inspect site content. |
184
187
  | `runtime_drain` | With `confirm=true`, stop admission on this connection; then close stdio and verify exact container/session resource termination. It is not workspace-wide down. |
@@ -135,6 +135,33 @@ unsafe-path refusal, symlinks, rollback and concurrent-edit recovery. Wheel test
135
135
  compare the complete top-level module inventory against source, excluding stale
136
136
  build-cache modules and the separate #116 checkpoint.
137
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.
138
+ ## Published delivery and post-release selection
139
+
140
+ [Release v0.7.4](https://github.com/dosquartsdedocs/unaltraweb/releases/tag/v0.7.4)
141
+ is public. PR119 supplies artifact source `676caa695d8e8f84a8a11800bb5a4a17599af539`;
142
+ PR120 supplies receipt/tag target `a0b82eadceac608a7e3ce97fb6d2fd2885dd541c`.
143
+ Annotated tag object: `7ef4525c33fd6ee4b9592deec23f1d87910a4581`.
144
+
145
+ - Controller: `ghcr.io/dosquartsdedocs/unaltraweb-mcp@sha256:10bcaf1411f27a518969283a77e23dcc99119014b216270b3089ba85ba0b6c7e`.
146
+ - Runtime: `ghcr.io/dosquartsdedocs/unaltraweb@sha256:5d82d15358f2785e1a548f8d3d2a0e932602e3d9d7b4d1efa330fb774c65f5cb`.
147
+ - Wheel SHA256: `0202ff0982fea276a7ba775245faa7bafd75acc5cfad3e1f549055e87cd336ec`.
148
+ - Handoff: [release-handoff.json](https://github.com/dosquartsdedocs/unaltraweb/releases/download/v0.7.4/release-handoff.json),
149
+ SHA256 `aaf6256f438cdb4500b3d96081a7a6edd013c44b3411744aa6738b18decbffb2`.
150
+
151
+ Trusted Publishing `40388093852`, OCI promotion `40388094024` and tag CI
152
+ `40388002315` passed. All fourteen original assets were downloaded anonymously
153
+ and matched their exact sizes/hashes, including both Docker archives. PyPI and
154
+ RubyGems bytes and OCI aliases matched. The public
155
+ [verification receipt](https://github.com/dosquartsdedocs/unaltraweb/releases/download/v0.7.4/verification.json)
156
+ has SHA256 `c19b46279100d48483ff544d87a3f88fae08d2bfc9b20f302628767ecaae8d09`.
157
+
158
+ The public wheel was installed in a new environment and passed the complete
159
+ synthetic installed-MCP, reviewed-conflict, stale-CAS and frozen Git/Bundler/Jekyll
160
+ acceptance: [acceptance.json](https://github.com/dosquartsdedocs/unaltraweb/releases/download/v0.7.4/acceptance.json).
161
+ The first invocation refused relative paths before running; the completed run
162
+ uses the required absolute paths. #115/#118 are closed with the
163
+ [full delivery](https://github.com/dosquartsdedocs/unaltraweb/issues/118#issuecomment-6426018149).
164
+
165
+ The post-release checkout launcher now selects the published controller digest
166
+ above. Existing sessions keep their loaded image; consumer/hub selection and
167
+ author review remain independent of this source pin and technical delivery.
@@ -451,7 +451,7 @@ def artifact_plan(project: Path, config: dict[str, Any], languages: list[str]) -
451
451
  return plan
452
452
 
453
453
 
454
- def manual_sources(project: Path, config: dict[str, Any], lang: str) -> tuple[Path | None, list[tuple[Path, dict[str, Any], str]], str]:
454
+ def manual_sources(project: Path, config: dict[str, Any], lang: str, *, for_pdf: bool = True) -> tuple[Path | None, list[tuple[Path, dict[str, Any], str]], str]:
455
455
  manual = nested(config, "unaltraweb", "manual")
456
456
  collection = str(manual.get("collection") or "chapters").strip()
457
457
  collection_root = safe_relative(project, f"_{collection}", label="manual collection", must_exist=True)
@@ -462,7 +462,10 @@ def manual_sources(project: Path, config: dict[str, Any], lang: str) -> tuple[Pa
462
462
  if path.suffix.lower() not in {".md", ".markdown"} or not path.is_file():
463
463
  continue
464
464
  front, body = read_source(path)
465
- if front.get("pdf") is False:
465
+ if for_pdf and front.get("pdf") is False:
466
+ continue
467
+ if not for_pdf and (front.get("published") is False or front.get("draft") is True
468
+ or (front.get("profiles") is not None and "unaltremanual" not in front["profiles"])):
466
469
  continue
467
470
  pages.append((path, front, body))
468
471