$ cat workspace-template.yaml
Generazione Power Point Polizia Postale
// Generazione Power Point con tema Polizia Postale
// Canvas Preview
// Instruction
Presentazione Polizia Postale dalle Cartelle Drive
Template ID
aec897f2-d1fa-438a-8935-8f10bda7f52d
Overview
Builds a self-contained Reveal.js deck from Drive documents using the Polizia Postale theme (navy/steel-blue header, Italian tricolor footer). For each (topic, slide) pair the agent clones a prototype, wires content from "Contenuto Presentazione", connects slide_html to "Make Array". Output assembled by Presentation Composer; published via "Public Share" (link) or downloaded via "PPTX Converter" (file, never auto-run). Publish decision collected at the Phase-1 gate.
Terminology: a topic has one or more slides (default 1). total_slides = sum of M_x. Final deck = #Intro + total_slides + #outro.
Page budget: page = slide. An explicit deck size P in the request is the TOTAL incl. #Intro + #outro → total_slides = P − 2. P is NOT a topic count (they differ for P > 3). Resolved at 3a-i, binding through step 6.
Two prototype chains ship on canvas — keep both (simple text chain + paired image chain; exact labels in Node Reference).
Workflow Chain
Data Source Selection
- Folder: "Seleziona Materiale Sorgente" (Folder Reader) + "Leggi i Documenti disponibili" (Document Reader).
- Single file:
deleteNode"Seleziona Materiale Sorgente"; configure only "Leggi i Documenti disponibili".
Node Reference
- "Seleziona Materiale Sorgente" (Folder Reader) — input
driveItemId(NOTfolderId); outputdriveItemIds. - "Leggi i Documenti disponibili" (Document Reader) — input
driveItemId; outputcontent. - "Selezione dei Topic Principali" — input
[content]; defaultprompt: "Seleziona i topic principali dei documenti e riassumi i punti chiave (topics), per ciascun topic riassumi i temi (slides) rilevanti"; outputsummary(extract topic + slide names verbatim). - "Contenuto Presentazione" — input
[content]; agent updatespromptper Phase 2 step 7; outputsummary(feeds #Intro, #outro, all topic Slide Generators). - "#Intro" —
polpostale-intro; pre-connected to Make Arrayitem_0. - "#outro" —
polpostale-outro; NOT pre-connected — agent wires to last pin. - Prototypes — DO NOT delete. Simple →
"Topic #x - Slide #1"(polpostale-content). Paired →"Topic #x - Slide #1 - [With Image Input]"(polpostale-image-left) +"Image Creation - for Topic #x - Slide #1 - [With Image Input]"; internalimage_creation.image → slide_gen.imagepreserved bycloneNodeswhen both IDs passed together. - Make Array —
item_0= #Intro;item_1..item_total_slides= topic slides (clone_index order);item_<total_slides+1>= #outro. Ships 10 pins (item_0…item_9) and does NOT auto-grow —upsertEdge/batchUpsertEdgesadd the edge but never the pin, so edges toitem_10+ land on handles the node doesn't draw. Whentotal_slides + 2 > 10, sync the schema at Step D2. - Presentation Composer —
theme: "polizia-postale"; pre-wired from Make Array. - PPTX Converter —
theme: "polizia-postale"; pre-wired from Composer; never auto-run. - Public Share — input
contentfrom Composer'spresentation; template IDa3f1d8c2-6e4b-5a9d-b7c3-2f8e1a4d6b9c(recreate if missing in Phase 4).
Polizia Postale Layout Selection
5 layouts; 3 pickable for topic slides.
Reserved (do NOT use for topic slides): polpostale-intro (#Intro), polpostale-outro (#outro). They embed the official stemma — NEVER wire a generated image to #Intro/#outro or swap their assets. No Image Creation node attaches to them.
Topic-slide layouts:
polpostale-content— text workhorse: header bar +<h2>+ free body (<p>,<ul>,<table>). (no image input)polpostale-image-left— image left, text right. (image input)polpostale-image-right— text left, image right. (image input)
Content density constraint (image-left/image-right ONLY): the text column is narrow. To prevent overflow: MAX 5 items per list, and AT MOST ONE main list per slide. No nested lists, no multiple consecutive lists. If the source is denser, condense to prose or split across additional slides.
Picking rule (by clone_index, 0-based):
useImagesChoice === "no"(or default) → every topic slide =polpostale-content.useImagesChoice === "yes"→ strictly alternate content and image layouts, content-first: even index (0,2,4…) →polpostale-content; odd index (1,3,5…) → an image layout, the image layouts alternatingpolpostale-image-leftthenpolpostale-image-right. Example (6 slides): content, image-left, content, image-right, content, image-left → 3 content / 3 image. HARD RULE: never make all topic slides image layouts (even indices keep ≥50% content); never silently fall back to all-content when images were requested — both families MUST appear (single topic slide → make it one image layout so images aren't absent).
Never use marina-* / emblema-*. Theme "polizia-postale" on BOTH Composer and PPTX Converter.
Important: Node IDs and Field Names
- After
applyCanvasData, always usenodeFinderby label. - Use atomic / batch tools for all modifications (no further
applyCanvasData). - Drive Reader input field is
driveItemId(NOTfolderId).
Execution Strategy
Complete all 4 phases in order. NEVER auto-run PPTX Converter. Public Share runs in Phase 4 iff publishChoice === "publish". After nodeExecutor the system notifies — do NOT poll. On error retry 3× then ask user. On "continua", resume via nodeFinder. NEVER execute prototypes directly.
Phase 1: Setup
applyCanvasData— IMMEDIATELY, before any other tool call.searchDriveItems+selectDriveItem— try shorter queries on no results (max 2 attempts) then ask user.- Data source:
- Folder:
nodeFinder"Seleziona Materiale Sorgente" →upsertNode({ nodeId, input: { driveItemId } }). - Single file:
deleteNode"Seleziona Materiale Sorgente";upsertNode"Leggi i Documenti disponibili" withdriveItemId.
- Folder:
3a. Phase 1 gate — two sub-steps: 3a-i (extract what the request already answers), then 3a-ii (ask only the rest). 3a-i is MANDATORY and runs first — it decides WHICH questions get asked at all.
3a-i — Known-answer extraction. Re-read the user's original message. Init known.topicCount = known.slidesPerTopic = known.useImages = known.imageStyle = known.publish = null, then fill:
EXPLICIT-ONLY RULE. Known = stated explicitly and unambiguously. If you must reason or estimate, it is NOT known — leave null and ASK.
- Vague size ("circa 5 pagine", "5-7 slide", "breve") and vague imagery ("qualche immagine", "maybe some photos") → NOT known.
- Never infer from tone, topic, audience or document type. Technical doc ≠
diagram; internal doc ≠draft; long source ≠ big deck. - Only sanctioned cross-key inference: an explicit style ⇒
useImages = "yes";useImages = "no"⇒imageStylemoot. - In doubt, fail open to ASKING. An extra question costs one line; a wrong extraction silently builds the wrong deck.
Page-budget decomposition (only on an explicit integer P): content_slides = P − 2; if < 1 → 1 with budgetTopics = budgetSlidesPerTopic = 1 (state the 3-page minimum); else budgetTopics = content_slides, budgetSlidesPerTopic = 1; if content_slides > 20, take the smallest S ∈ 2..10 with content_slides % S == 0 and content_slides / S ≤ 20 → budgetSlidesPerTopic = S, budgetTopics = content_slides / S. Set known.topicCount / known.slidesPerTopic from these — so neither question is asked. No explicit P → pageBudget = null.
Conflict: P plus an explicit per-key number → the per-key number WINS, derive the other from content_slides (max(1, round(...))), recompute pageBudget, and say so in the print line.
Print what was extracted and what remains, e.g. Già nella richiesta: 5 pagine (→ 3 topic × 1 slide), niente immagini. Chiedo solo: pubblicazione. No print line = 3a-i not run.
Unit discipline: P is a PAGE total, budgetTopics a TOPIC count. Answering "5 topic" to a "5 pagine" request yields 1+5+1 = 7 pages — a defect, not rounding.
3a-ii — ONE requestUserDecision with ONLY the keys still null (italiano, canonical order below); additionally drop imageStyle when known.useImages === "no". Present each included question unchanged — never re-encode an extracted value into its options.
topicCount— "Quanti topic principali?" options3/5/10/auto(free-text accepted as integer ≤ 50).slidesPerTopic— "Quante slide per topic?" options1/2/3/auto(free-text accepted as integer ≤ 10).useImages— "Includere immagini generate automaticamente?" optionsyes/no. Context note: "#Intro e #outro NON ricevono mai immagini generate."imageStyle— "Stile immagini?" optionsphoto/diagram. Used only ifuseImages === "yes". Keep it wheneveruseImagesis itself being asked (no mid-card branching) and discard the answer if the user picksno.publish— "Pubblicare automaticamente (link condivisibile)?" optionspublish/draft. Context note: "PPTX NON viene generato automaticamente."
ZERO remaining → do NOT call requestUserDecision at all. questions is .min(1).max(6), so [] is a schema error — and pausing to ask nothing is worse than not pausing. Print the resolved set, treat the result as answers = [], go to the merge. Call the tool at most once in Phase 1, whatever the subset size.
Merge: asked → the gate answer wins; not asked → known.<key> IS the answer. Defaults when a question was asked and cancelled/missing: topicCountChoice → auto; slidesPerTopicChoice → auto; useImagesChoice → no; imageStyleChoice → photo; publishChoice → draft. known.publish === "publish" IS the user's explicit publish choice (asked for in their own words) — NEVER publish on null / draft / cancelled. pageBudget / budgetTopics / budgetSlidesPerTopic carry forward; a cancelled card retracts nothing extracted at 3a-i.
Phase 2 entry precondition: all five VALUES resolved (extracted or answered) — however many questions were actually asked, including zero. Any missing → STOP, re-run 3a-i, ask the remainder in ONE call.
Phase 2: Topic Selection & Content Generation
- Resolve first.
topicCountChoice/slidesPerTopicChoicecome from the 3a-ii merge. IfpageBudgetset and either is stillauto→ take it frombudgetTopics/budgetSlidesPerTopic(safety net — with a budget neither should have been asked). IfpageBudgetset and either is a number differing from the decomposition → keep the number and recomputepageBudget = 1 + topicCountChoice × slidesPerTopicChoice + 1. PrintStruttura risolta: <N> topic × <M> slide = <pageBudget|n/d> pagine.ThennodeFinder"Selezione dei Topic Principali". Configure:- Both
autoANDpageBudgetnull → default unchanged. - Otherwise →
upsertNode({ nodeId, input: { prompt: "Seleziona <N> topic principali dei documenti e per ciascun topic seleziona <M> temi (slides) rilevanti" } }). Replace<N>/<M>(or"i topic"/"i temi"if auto). WhenpageBudgetset, append" La presentazione finale deve avere esattamente <pageBudget> pagine: intro + <N>×<M> slide di contenuto + outro."Append user's focus area if any.
- Both
nodeExecutor"Selezione dei Topic Principali" (auto-runs Document Reader). Wait.getNodeOutput→ extracttopics,slides[X],N,M_x. Names verbatim. Cap N / M_x to the resolved integers if set. Budget reconciliation (whenpageBudgetset):total_slidesMUST equalpageBudget − 2. Too high → drop trailing slides (last topic first). Too low → add slides round-robin from Topic #1, naming each from a sub-theme already present under that topic in the selector output (never invent a topic name); if the material genuinely can't support the count, STOP and ask rather than silently shrinking. PrintBudget: <pageBudget> pagine = 1 intro + <total_slides> contenuto + 1 outro.total_slidesis now the planned slide count that step 9b, step 16a and step 20 must all agree with. IfN > 20ortotal_slides > 50, ask whether to proceed/reduce.nodeFinder"Contenuto Presentazione" →upsertNodesettingprompt:
Replace placeholders with real names from step 6.
8. nodeExecutor "Contenuto Presentazione" IMMEDIATELY after step 7. Wait.
Phase 3: Slide Chain Creation
6 sequential steps (A→B→C→D→D2→E). Each batch tool called exactly once per step — patch mistakes with single-op tools. Do NOT delete prototypes.
Step A — Find prototypes, build mapping table, clone:
- Find by
useImagesChoice:no→simplePrototypeIdonly.yes→imageSlidePrototypeId+imageCreationPrototypeIdANDsimplePrototypeId(text rows still need it). Both branches alsonodeFinder"Contenuto Presentazione" and "Make Array".
9b. Build IMMUTABLE mapping table. Per topic X (1..N) per slide Y (1..M_x): sequential clone_index from 0; pin = item_<clone_index+1>; pick layout per the Picking rule — no: all polpostale-content; yes: alternate content/image content-first by clone_index (even=content, odd=image; images alternate left/right), never all-image. Print the table.
9c. (Yes branch ONLY — MANDATORY before step 10.) Partition by IMAGE_LAYOUTS: image_rows / text_rows complement, sum = total_slides. Print both lists. If image_rows.length === 0, skip the image clone call.
- Clone:
- No:
batchCloneNodes({ nodeIds: [simplePrototypeId], count: total_slides })→clones[i]. - Yes (skip a call if its count is 0):
- Text:
batchCloneNodes({ nodeIds: [simplePrototypeId], count: text_rows.length })→textClones[t]. - Image:
batchCloneNodes({ nodeIds: [imageCreationPrototypeId, imageSlidePrototypeId], count: image_rows.length })→imageClones[g].nodeIdMaphas BOTH IDs (internalimage_creation.image → slide_gen.imageedge preserved).
- Text:
- Spot-check one image pair survived; patch with
upsertEdgeif needed.
Step B — Rename + instruction + layout in ONE batchUpsertNodes:
- Cloned nodes inherit prototype label/instruction/
template_name— overwrite all three per clone.
Per row: slide-gen op { nodeId: <slideGenCloneId>, label: "Topic #X - Slide #Y", input: { instruction: "<INSTRUCTION>", template_name: "<layout from mapping table>" } }.
<INSTRUCTION> base: "Inserisci il contenuto del Topic #X '<topicX_name>' - Slide #Y '<slides[X][Y]>'".
For image-left / image-right rows, append: " MAX 5 voci per lista, UNA SOLA lista principale per slide; condensa in prosa o spezza in più slide se il contenuto è più denso. Niente liste annidate."
Image rows ALSO get an image-creation op: { nodeId: <imageCreationCloneId>, label: "Image - Topic #X - Slide #Y", input: { prompt: <PROMPT> } }.
<PROMPT> (per imageStyleChoice, both reference the slide's topic + slide name, palette navy/blu/bianco con accenti tricolore istituzionali):
- photo: realistic editorial photography of people/places/atmospheres; NO icons, text, vector graphics, diagrams.
- diagram: editorial diagram with icons, label text, vector schemes; clear composition.
Total ops: No = total_slides; Yes = text_rows.length + 2 × image_rows.length. Instructions MUST include exact names. template_name MUST be polpostale-content / -image-left / -image-right. NEVER assign an Image Creation node to #Intro or #outro.
Step C — Wire content (ONE batchUpsertEdges): for each slide-gen clone: { sourceNodeId: <Contenuto Presentazione ID>, sourcePort: "summary", targetNodeId: <slideGenCloneId>, targetPort: "content" }. Image Creation clones get NO content edge. Total: total_slides edges.
Step D — Wire to Make Array + #outro (ONE batchUpsertEdges): nodeFinder "#outro" first. Per row: { sourceNodeId: <slideGenCloneId>, sourcePort: "slide_html", targetNodeId: <Make Array ID>, targetPort: "item_<clone_index+1>" }. Last: #outro on item_<total_slides+1>. item_0 RESERVED for #Intro. The edges array must contain exactly total_slides + 1 entries (one per planned slide + #outro) — count them before moving on; step 16a re-derives the same roster from the canvas and blocks on any mismatch.
Step D2 — Sync Make Array pins (REQUIRED when total_slides + 2 > 10): Make Array ships 10 pins and batchUpsertEdges does NOT grow them, so edges to item_10+ hit handles the node never draws. Fix with ONE updateNodeSchema call replacing the WHOLE inputSchema with exactly item_0 … item_<total_slides+1>:
It replaces (never merges) and prunes edges to any pin omitted — list EVERY pin, never fewer, never below 10. Skip entirely when total_slides + 2 ≤ 10.
Step E — "Topic Slides" section (MANDATORY for ≥3 clones). Full clone-ID set = every slide-gen clone + every image-creation clone (Yes). Four sub-steps in order:
a. sectionFinder prototype's parent section → sectionManager({ action: "ungroup", sectionId }) (string ONLY).
b. organizeNodes({ nodeIds: [<full set>] }).
c. sectionManager({ action: "group", nodeIds: [<full set>], label: "Topic Slides" }). If section exists, ungroup it FIRST.
d. autoLayout() (direction: "LR"). MANDATORY.
Phase 4: Verification & Final Execution
Order: 16 → 16a → 17 → 18 → 19 → 20. No user pauses. The delivered deck has exactly as many slides as Make Array has OCCUPIED PINS — not the clones you created, not your mapping rows, not the topics you announced. Every slide count you state (step 18 summary, step 20 checklist and wrap-up) MUST be the count measured at 16a. Announcing an unmeasured count is reporting a result that does not exist.
nodeFinderMake Array + all Slide Gens + Composer + PPTX Converter + Public Share. (Make Array membership is audited at 16a — this step is the per-node pass.) Verify and patch withupsertEdge/upsertNode:
- #Intro on
item_0; #outro on last pin; neither has an image input (delete any orphan edge/node). - Every topic Slide Gen has a
contentedge from "Contenuto Presentazione". template_name∈ {polpostale-content,-image-left,-image-right} (NEVER intro/outro/marina-*/emblema-*).- Image-left/right instructions carry the MAX-5-items / 1-list constraint.
- Theme
"polizia-postale"on BOTH Composer AND PPTX Converter. - Yes mode: every image-row slide-gen has BOTH
contentANDimageedges; every Image Creation clone has a non-empty per-slideprompt; layouts alternate content/image (content-first), ≥ every other topic slide ispolpostale-content— never all-image. - Composer
presentation→ Public Sharecontentedge present; "Topic Slides" section exists. - Make Array
inputSchemalists ≥total_slides + 2item_*pins — the node must display them, not merely have edges to them. Fewer → Step D2 was skipped; fix with the sameupdateNodeSchemacall.
16a. Make Array membership audit — BLOCKING. Observed failure: the agent announced "10 slide totali" and success while Make Array held only item_0 (#Intro) and item_11 (#outro) — every content pin empty, delivered deck 2 slides. Do NOT trust the mapping table, the batch call, or your memory of what you wired. Read the canvas.
a. Expected roster from 9b: item_0 = #Intro; item_<clone_index+1> = each mapping row; item_<total_slides+1> = #outro. Expected occupied = total_slides + 2.
b. Actual: nodeFinder Make Array, enumerate incoming edges as (targetPort, source label). If incoming edges aren't exposed, read from the source side — any Slide Gen with outputs: [] is NOT connected, whatever the plan says.
c. Print the roster table (pin | expected | actual | OK/MISSING/DUPLICATE). Can't print it → you didn't audit; go back to (b).
d. Checks: (1) every pin item_0 … item_<total_slides+1> has exactly one incoming edge; (2) no shared pins, no node on two pins, no gaps — item_0 + item_11 on an 11-slide plan is 2 slides, not 11; gaps are the signature of this failure; (3) actual_slide_count = occupied pins, and it must equal total_slides + 2.
e. Pass → state Composizione verificata: <actual_slide_count>/<total_slides + 2> slide collegate. → step 17.
f. Fail → repair ONCE, single-op only: upsertEdge per missing pin; deleteEdge + upsertEdge per duplicate. Never re-run batchUpsertEdges (already spent in Step D). A mapping row with no clone at all is a Step A/B failure, not a wiring one — say so explicitly. Then re-run (b)–(d) exactly once.
g. Still failing → STOP. Do NOT loop, do NOT run step 19. Go to step 20 and report honestly: one error item per empty pin naming the slide that should occupy it, plus "Composizione incompleta: <actual_slide_count>/<total_slides + 2> slide collegate — la presentazione conterrà <actual_slide_count> slide." Reporting the planned count as delivered is a failure of this step, not a rounding of it.
actual_slide_count is the ONLY slide number quotable from here on.
-
nodeFinder({ query: "Public Share" }). If missing ANDpublishChoice === "publish"→ recreate withupsertNode({ templateId: "a3f1d8c2-6e4b-5a9d-b7c3-2f8e1a4d6b9c" })+upsertEdgefrom Composer. If missing ANDdraft→ leave unset. Store<publicShareId>. -
One-sentence summary that the deck is built. If
publishChoice === "publish"AND<publicShareId>set → step 19; otherwise skip 19, note "in bozza". -
nodeExecutor({ nodeId: <publicShareId> })(only when step 18 said to). System auto-runs the upstream chain; result card shows/s/{slug}. Never auto-run PPTX Converter. -
verification— present checklist (info ✓ / warning / error) covering the step-16 items, the 16a composition result (info✓ only if 16a passed; if it failed after its repair pass, oneerrorper empty pin plus the incomplete-composition item), and execution status (✓ "Public Share eseguito; URL/s/{slug}" OR info "bozza — esegui Public Share / PPTX Converter su richiesta"). Summary:"Verifica finale presentazione Polizia Postale: <N> controlli, <E> errori, <W> warning."Include N topics, M_x slides/topic, total =actual_slide_countmeasured at 16a (NOT the plannedtotal_slides + 2— they match only when 16a passed, which is why you quote the measured one), theme = Polizia Postale, and either the share URL or the draft note. WhenpageBudgetwas set, stateRichieste <pageBudget> pagine — consegnate <actual_slide_count>.; if those differ, lead with it and do NOT describe the run as successful.verificationis terminal — do NOT callfollowUp. On errors, wait for user fix.
Incremental Edits (deck pre-existed this turn)
Do NOT re-run Phase 1 gate or Phases 2/3. Apply the delta, re-run the 16a roster audit (recomputing total_slides and actual_slide_count), then step-20 verification, then if previously published re-run nodeExecutor on Public Share; else leave draft. Past 10 pins, re-run Step D2 whenever the pin count changes. Bundled "build AND tweak" = fresh build.
- Add a slide:
upsertNode({ templateId: "69bba2bf-591b-5e7b-932b-6a705d4b9b87", label, input: { template_name, instruction } })→ content edge → insert in Make Array (shift later pins) →organizeNodes+autoLayout. Image slide: also create + wire + prompt the Image Creation node; instruction enforces MAX 5 items / 1 main list. To insert inside "Topic Slides", ungroup first then re-group. - Remove:
deleteNode(also paired Image Creation) → close pin gap → re-layout. - Reorder: re-assign
item_<n>pins viaupsertEdge(#Intro stays onitem_0, #outro last).
Common User Requests → Configuration
Error Handling
- Announced slide count ≠ delivered ("10 slide" reported, 2 in the deck) → Make Array had empty pins: Step D's
batchUpsertEdgesnever issued, partial, or aimed at clones that were never created. 16a exists to catch this — no roster table printed means it was skipped. Never state an unmeasured count. - Delivered pages ≠ requested pages → budget lost: 3a-i must set
pageBudgetand print, step 4 must resolve it, step 6 must reconciletotal_slidestopageBudget − 2. Unit error: "5 pagine" answered as "5 topic" → 7 pages. - Make Array shows fewer pins than edges wired into it (>10 connections, 10 pins drawn) → Step D2 skipped;
updateNodeSchemawithitem_0 … item_<total_slides+1>(it replaces and prunes omitted pins — list every one). - Empty slides → missing content edge;
upsertEdgeContenuto Presentazione[summary]→ Slide Gen[content]. - Image-left/right text overflows → instruction missed MAX 5 items / 1 main list rule; fix instruction, re-execute.
- Image Creation attached to #Intro/#outro →
deleteEdgeand delete the orphan Image Creation node. - Image Creation prompt empty / image edge missing →
upsertNode(prompt) orupsertEdge(Image Creation[image]→ Slide Gen[image]). - Theme drift / wrong layout family (marina-* / emblema-*) →
upsertNodetotheme: "polizia-postale"and/or swap to polpostale layout on BOTH Composer AND PPTX Converter. - Public Share missing / blank share page →
upsertNode({ templateId: "a3f1d8c2-…" })+ reconnect from Composer; if blank, verify edge and re-execute. - PPTX never produced → expected (never auto-run); execute on explicit request only.
- Canvas broken after Phase 3 → Step E skipped; run full
ungroup → organize → group → autoLayout. ungroupschema error →nodeIdswas passed;ungrouptakes ONLYsectionId(string).group"already in a section" → do NOT retry; ungroup first, organize, re-group, autoLayout — or skip grouping (new node stays standalone).
Cross-references
apps/workspace-service/app/templates/presentation_composer.py—_PP_CSS,CUSTOM_THEMES["polizia-postale"].apps/workspace-service/app/templates/slide_generator.py— 5polpostale-*entries.- Siblings:
pptx-from-drive.md(Marina),pptx-from-drive-emblema.md(Emblema).
// Dependencies
1from input import DriveFolderReader2from input import DriveDocumentReader3from process import TextSummarizer4from process import SlideGenerator5from process import ImageCreation6from process import MakeArray7from output import PresentationComposer8from output import PublicShare9from output import PPTXConverter$ git log --oneline
v1.1.0 — user-input composition (known-answer bypass incl. page-budget resolution), blocking Make Array membership audit (16a) with honest reporting, and Step D2 updateNodeSchema pin-sync (fixes the false auto-grow-past-10-pins claim).