返回 ppt-master
verify-charts.md
根目录 / skills / ppt-master / workflows / stages / verify-charts.md
1 ---
2 description: Conditional quality-gate stage for data-chart geometry and encoding verification.
3 ---
4
5 # Verify Charts Stage
6
7 > Conditional Generate-PPTX quality stage. Run after a deck containing data charts has finished SVG generation, before post-processing & export. Catches coordinate and visual-encoding errors introduced while mapping source values into SVG marks.
8
9 In Default Generate this stage is **context-independent**: it reads
10 `design_spec.md` and the generated SVGs, then runs the calculator script. The
11 lockless Quick branch is deliberately context-dependent: run it in the same
12 active session from the page decisions just authored. If that context is lost,
13 restart Quick rather than inventing a page plan from finished files.
14
15 ## When to Run
16
17 - The deck contains one or more data visualization charts where source values determine SVG geometry or visual encoding: bar lengths/heights, point positions, arc angles, polygon vertices, connector endpoints, bubble centers/radii, flow widths/paths, cell colors, or word sizes.
18 - SVGs are generated to `<project_path>/svg_output/`. Default enters from its declared quality-gate order; Quick runs this stage before its one lockless final checker.
19 - Post-processing (`finalize_svg.py`, `svg_to_pptx.py`) has **not yet** run.
20
21 The calculator has direct CLI models for simple bars, lines/scatter, pie/donut, radar, and grid layouts. Composite/derived charts are **not automatically out of scope**: if their geometry reduces to repeated direct calculations, include them as `decomposable-calc`; if the calculator has no layout model but the SVG geometry is still data-driven, include them as `manual-verify` so they are not silently skipped.
22
23 ---
24
25 ## Step 1: Build the chart-object list from the active profile authority
26
27 | Active profile | Object-list authority |
28 |---|---|
29 | Default Generate | `design_spec.md §IX` plus the legacy §VII fallback below |
30 | Quick Generate | The still-active semantic object keys and page decisions that produced the SVGs, cross-checked against every `chart-plot-area` marker; no Design Spec, lock, or substitute planning artifact is created |
31
32 For Default, read `<project_path>/design_spec.md` §IX Content Outline as the
33 authoritative roster and include every semantic object key whose
34 `Visualization` entry declares SVG geometry driven by data values. Cross-check
35 §VII only to resolve a selected catalog reference; absence means no reusable
36 reference was selected. For a legacy spec whose §IX predates object keys, one
37 real §VII data-chart row may supply one legacy chart object for that page.
38
39 For Quick, enumerate every promoted chart object's semantic key and page, then
40 search `svg_output/` once for `chart-plot-area`. Compare objects and marker
41 wrappers one-for-one. Add a missing scoped marker before continuing;
42 investigate an unexpected marker instead of silently adding or dropping an
43 object. Keep the list in active context only.
44
45 Classify each included chart object into exactly one mode:
46
47 Incidental microvisuals not promoted under the active profile authority are not
48 inferred into this list. Default repairs that object's §IX `Visualization` first;
49 Quick makes the promotion decision immediately in active context and updates
50 the SVG marker before verification.
51
52 | Mode | `charts_index.json` keys | Notes |
53 |------|--------------------------|-------|
54 | `direct-calc` | `column_chart`, `horizontal_bar_chart`, `histogram_chart` | Use `calc bar`; add `--horizontal` for horizontal bars. Histogram bins use contiguous bars on the numeric x-axis. |
55 | `direct-calc` | `line_chart`, `area_chart`, `scatter_chart` | Use `calc line`; area uses line output as the top boundary, then closes to `y_max`. |
56 | `direct-calc` | `pie_chart`, `donut_chart` | Use `calc pie`; donut passes `--inner-radius`. |
57 | `direct-calc` | `radar_chart` | Use `calc radar`; separate subcommand, not under `calc pie`. |
58 | `decomposable-calc` | `stacked_bar_chart`, `stacked_area_chart`, `grouped_bar_chart`, `dumbbell_chart`, `pareto_chart`, `dual_axis_line_chart`, `bullet_chart`, `butterfly_chart`, `waterfall_chart`, `box_plot_chart`, `gantt_chart`, `bar_of_pie_chart`, `pie_of_pie_chart`, `stock_chart` | Verify by repeated direct calculations; see recipes below. |
59 | `partial-calc` | `bubble_chart`, `matrix_2x2` | Use `calc line` for x/y-driven `cx/cy`; verify radius only when a size scale is explicit. |
60 | `formula-verify` | `progress_bar_chart`, `gauge_chart`, `funnel_chart`, `sunburst_chart` | Record the formula and resulting length/angle/width in the receipt; sunburst verifies each ring's value-derived arc lengths and offsets. |
61 | `manual-verify` | `sankey_chart`, `heatmap_chart`, `treemap_chart`, `word_cloud` | Data-driven geometry or encoding exists, but the current calculator has no complete layout model. Inspect and report; do not silently skip. |
62
63 **Family boundary**: this table covers every canonical key in
64 `templates/charts/charts_index.json` exactly once. Do not put qualitative shape
65 composition or a Table reference in the receipt merely because it contains
66 shapes or numbers. Named quadrants are composed through
67 [`executor-structure.md`](../../references/executor-structure.md);
68 `chart/matrix_2x2` is reserved for plotted x/y and optional radius data. Every
69 embedded data chart is its own keyed §IX `Visualization` object.
70
71 Resulting list:
72
73 ```
74 P03 market-share 03_market_share.svg type=bar mode=direct-calc
75 P03 margin-trend 03_market_share.svg type=line mode=direct-calc
76 P11 share-split 11_share_split.svg type=pie mode=direct-calc
77 P15 pareto-causes 15_pareto.svg type=pareto mode=decomposable-calc
78 ```
79
80 In Default, if §VII is absent, continue from §IX; this is the normal state when
81 all chart objects use custom structures. Do not guess from SVG content when §IX
82 declares no data-driven object. In Quick, marker search is only the required
83 cross-check, never a replacement for active authoring decisions.
84
85 If the filtered list is empty, output `verify-charts: active profile declares no data-driven chart objects, nothing to verify` and stop.
86
87 ---
88
89 ## Step 2: Per object — read its SVG scope, calculate, compare, update
90
91 For each object in the Step 1 list:
92
93 1. Read `<project_path>/svg_output/<page>.svg`.
94 2. Locate `<g id="<object-key>">` and its one plot-area marker. The marker
95 payload starts `chart-plot-area: object=<object-key> |` and belongs inside
96 `<g id="<object-key>-chartArea">`. Accept a legacy unscoped marker and
97 `id="chartArea"` only when the page has exactly one verified chart. A
98 multi-chart page may not mix scoped and unscoped markers. If a marker is
99 missing, derive it from that object's axes or center/radius and add the
100 scoped marker before continuing.
101 3. Read only that object's data series and label/value elements.
102 4. **Read axis tick labels for every axis-based chart inside the same object scope.** Locate the `<text>` elements along the value axis — X-axis labels for horizontal bars, Y-axis labels for vertical bars, and Y-axis labels for line-like charts. Extract the first and last tick values to determine the axis range (e.g. `0%` to `120%` → range `0,120`). Pass this range as `--value-range`, `--y-range`, or `--x-range` as appropriate. Use the attached `--*-range=min,max` form, which also keeps a negative minimum from being parsed as another option. Radar uses `--max-value` instead of a range: read the outermost ring's tick value and pass it as `--max-value`. If the SVG has no explicit tick labels (data labels only, no grid), omit the range and let the calculator auto-normalize — but flag the receipt as `scale=auto (no ticks)`.
103
104 **Local vs absolute coordinates.** Many chart templates wrap chart content in `<g transform="translate(cx, cy)">` or similar, so child `<circle>`/`<polygon>`/`<rect>` coords are relative to that origin (e.g. radar polygon at `0,-198`, donut paths starting from `0,0` inside a translated `<g>`, dumbbell circles at `cy="0"` inside a per-row translated `<g>`). The calculator outputs **absolute** SVG coordinates. Before comparing, either add the wrapping translate's offset to the SVG coords or subtract it from the calculator's output — pick one direction and apply it consistently.
105 5. Run the matching calculator command:
106
107 ```bash
108 # column_chart / horizontal_bar_chart (add --horizontal for the latter)
109 # IMPORTANT: always pass --value-range from axis tick labels (step 4)
110 python3 skills/ppt-master/scripts/svg_position_calculator.py calc bar \
111 --data "Label1:Value1,Label2:Value2" --area "x_min,y_min,x_max,y_max" \
112 --bar-width 120 --value-range=0,axis_max
113
114 # line_chart / area_chart / scatter_chart — area uses line output as the top boundary, then closes to y_max
115 python3 skills/ppt-master/scripts/svg_position_calculator.py calc line \
116 --data "x1:y1,x2:y2,..." --area "x_min,y_min,x_max,y_max" --y-range=0,max
117
118 # pie_chart — default start angle is -90 (12 o'clock); pass --start-angle only if the SVG starts elsewhere
119 python3 skills/ppt-master/scripts/svg_position_calculator.py calc pie \
120 --data "Slice1:Value1,Slice2:Value2" --center "cx,cy" --radius 200 --start-angle -90
121
122 # donut_chart (pie with inner-radius)
123 python3 skills/ppt-master/scripts/svg_position_calculator.py calc pie \
124 --data "Slice1:Value1,Slice2:Value2" --center "cx,cy" --radius 200 --inner-radius 120 --start-angle -90
125
126 # radar_chart (separate subcommand) — pass --max-value from the outermost ring tick
127 python3 skills/ppt-master/scripts/svg_position_calculator.py calc radar \
128 --data "Dim1:Value1,Dim2:Value2,Dim3:Value3" --center "cx,cy" --radius 200 --max-value 100
129 ```
130
131 Area chart fill path closes to the bottom edge of the plot area:
132
133 ```svg
134 M first_x,first_y ... L last_x,last_y L last_x,y_max L first_x,y_max Z
135 ```
136
137 6. **Scale-aware comparison.** Compare calculator output against the SVG's existing coordinates. Before declaring a mismatch, verify that every calculator invocation used the same axis range, plot area, center/radius, start angle, or size scale that the SVG visually declares. For `calc bar`, the output header must show `Value scale: axis ticks (...)` when the SVG has explicit ticks; if it shows `auto (max*1.1)`, go back to step 4 and re-run with the correct `--value-range`. **Do NOT update the SVG with mismatched-scale output.** Only update SVG attributes when the scale is confirmed to match and coordinates genuinely differ. Update by hand (do NOT use regex / bulk replacement — coordinates are positional and easy to swap incorrectly).
138
139 After updating any page, follow the active profile's checker order. Default
140 reruns its quality checker to confirm nothing broke:
141
142 ```bash
143 python3 skills/ppt-master/scripts/svg_quality_checker.py <project_path>
144 ```
145
146 Quick completes every chart comparison/repair first, then returns to
147 `quick-generate.md` §4 and runs its one lockless final checker. Do not insert a
148 checker call between Quick chart pages.
149
150 ---
151
152 ## Stacked recipe
153
154 `stacked_bar_chart` and `stacked_area_chart` are not single-call but reduce cleanly to repeated calls on existing primitives. The operator already had to compute cumulative values to draw the SVG — verify-charts reuses them.
155
156 **Stacked bar** — for N stacked series on the same x categories, run `calc bar` N times. Pass each segment's **height** as the data value, and shift `--area`'s `y_max` down by the sum of all lower segments for that category. Compare each segment's `(x, y, width, height)` against the SVG.
157
158 ```bash
159 # Example: two-series stack at category "Q1" with bottom=30, top=20, plot area y from 100 to 500
160 # Run 1 — bottom segment (origin = baseline)
161 python3 skills/ppt-master/scripts/svg_position_calculator.py calc bar \
162 --data "Q1:30,Q2:..." --area "x_min,100,x_max,500" \
163 --bar-width 80 --value-range=0,axis_max
164 # Run 2 — top segment (origin shifted up by bottom segment's height in pixels)
165 python3 skills/ppt-master/scripts/svg_position_calculator.py calc bar \
166 --data "Q1:20,Q2:..." --area "x_min,100,x_max,<500 - bottom_height_px>" \
167 --bar-width 80 --value-range=0,axis_max
168 ```
169
170 **Stacked area** — for N stacked series, run `calc line` N times on **cumulative** y-values (series 1 raw; series 2 = series1+series2; …). Each call yields the top boundary of one band. Each band's SVG path closes to the **previous** band's top boundary (not to `y_max`).
171
172 If a stack page's segment positions don't reduce to this recipe (e.g., negative segments, percent-stacked with non-100 totals), mark it `manual-verify` in the receipt and inspect by hand — do not silently pass.
173
174 ---
175
176 ## Decomposable recipes
177
178 Use these recipes for `decomposable-calc` and `partial-calc` pages. Each recipe must produce a receipt line; if a page cannot be reduced cleanly, mark `manual-verify` with the reason instead of dropping it.
179
180 **Dumbbell chart** — for before/after or two-state values across categories. The two endpoints are **points**, not bar ends — `calc bar --horizontal` always anchors at `x_min`, which only matches the right endpoint. Use `calc line` × 2 instead, treating category index as the y axis:
181
182 1. Number categories `0.5, 1.5, …, N-0.5` so each row's y lands on its band center; set `--y-range=0,N`. The same convention applies to vertical dumbbells with the axes swapped.
183 2. Set `--x-range` to the shared value-axis range read from ticks.
184 3. Run `calc line` once per endpoint series with identical `--area`, `--x-range`, `--y-range`. Each output `(SVG_X, SVG_Y)` is the matching endpoint circle's `(cx, cy)`.
185 4. Compare both endpoint circles and the connector line (`x1=cx_left, x2=cx_right, y1=y2=cy`) against the two calculated point sets.
186
187 ```bash
188 # Horizontal dumbbell, 3 categories, value axis 0–100, plot area (100,100)–(700,460).
189 # Encode category index as the y value: row 1 → 0.5, row 2 → 1.5, row 3 → 2.5.
190 python3 skills/ppt-master/scripts/svg_position_calculator.py calc line \
191 --data "42:0.5,55:1.5,37:2.5" --area "100,100,700,460" \
192 --x-range=0,100 --y-range=0,3
193 python3 skills/ppt-master/scripts/svg_position_calculator.py calc line \
194 --data "68:0.5,71:1.5,49:2.5" --area "100,100,700,460" \
195 --x-range=0,100 --y-range=0,3
196 ```
197
198 **Pareto chart** — split into descending bars plus cumulative line:
199
200 1. Run `calc bar` on the descending category values with the bar axis range from ticks.
201 2. Precompute cumulative percentages in category order.
202 3. Run `calc line` on `0.5:cum1,1.5:cum2,...,N-0.5:cumN` with `--x-range=0,N`, the right-side percentage axis as `--y-range` (usually `--y-range=0,100`), and the same `--area` as the bars. The `n - 0.5` offset puts each cumulative point on the matching bar's center; using `1,2,…,N` shifts the polyline left by half a bar width.
203 4. Compare bar rects, cumulative line path, and cumulative markers separately.
204
205 **Dual-axis line chart** — split by axis:
206
207 1. Read the left and right Y-axis tick ranges independently.
208 2. Run `calc line` once per series using its own `--y-range`; use the same `--x-range` and plot area for both.
209 3. Compare each series' polyline/path points against the matching axis scale. Never use the left-axis scale for the right-axis series or vice versa.
210
211 **Bullet chart** — performance bands + actual bar + target marker, all anchored at the same `x_min`. The bands occupy the **same** y row (they stack visually by overlapping, not by category), so run `calc bar --horizontal` once **per band** with a single data point — multi-category calls would spread y across rows:
212
213 1. Read the value-axis range from the band edges (the widest band's right edge = axis max).
214 2. For each band, run `calc bar --horizontal --data "<band_name>:<right_edge_value>" --area "<x_min>,<band_y>,<x_max>,<band_y+band_height>" --bar-width <band_height>`. Each call returns one rect at the shared `(x_min, band_y)` with the value-mapped width. Compare against the band rect.
215 3. Run `calc bar --horizontal` with a single data point for the actual value, using the actual bar's inset area (`y` and `bar-width` shrunk so the bands are visible). Compare against the actual rect.
216 4. The target marker is a `<line>` at `x = x_min + target/axis_max × area_width`, spanning the full band height. Compute by hand and compare.
217
218 **Butterfly chart** — mirrored horizontal bars around a vertical center line at `cx`:
219
220 1. Read the value-axis range and the center-line `cx` from the SVG.
221 2. Run `calc bar --horizontal` once per side using a plot area whose `x_min = cx` and `x_max = cx + side_width`. The right-side bars' `x` and `width` map directly.
222 3. For the left side, reuse the same calc output and mirror: each left bar's `x = cx - width`, `width` unchanged. Compare against the left rects.
223 4. Category `y` is shared across both sides — verify left and right rows align on the same `y + height/2`.
224
225 **Grouped bar chart** — N series sharing the same x categories, side-by-side instead of stacked:
226
227 1. Read the value-axis range and the plot area.
228 2. Compute the inner-group spacing: if there are `N` series and the visual group spans width `W` per category, each series-bar's width is `W/N` and its x offset within the group is `(i - 1) × W/N`. Read these from the SVG (the first category's bars give you both).
229 3. Run `calc bar` once per series with the **same** `--area` and `--value-range` but with each call's `--bar-width` set to the inner width. The calc's per-category center X gives the **group** center; each series-bar's actual `x = group_center - W/2 + (i-1) × W/N`. Compare against the SVG.
230
231 **Box plot chart** — Q1/Q3 box + median line + whiskers. All five quantities are y-values on the same axis:
232
233 1. Read the y-axis range and plot area. For each category, the five values are min / Q1 / median / Q3 / max.
234 2. Run `calc bar` once treating each category's box (Q3 − Q1) as a synthetic "stacked" segment with the area's `y_max` shifted to `y_axis_top - Q1 × pixels_per_unit` (the Q1 baseline). The output's `y, height` should match the box rect.
235 3. Median y = `y_axis_top + (axis_max - median) × pixels_per_unit`. Whisker endpoints (min, max) follow the same formula. Compare each against the SVG's `<line>` y1/y2 and `<rect>` y/height.
236
237 **Gantt chart** — task bars where each bar's `x` and `x + width` are the start and end positions on a timeline axis:
238
239 This remains a Chart even when the source used a physical PowerPoint table for
240 the row grid. A qualitative stage/lane plan whose positions are not derived
241 from dates or durations uses [`executor-structure.md`](../../references/executor-structure.md)
242 and does not enter this verification stage.
243
244 1. Read the timeline tick positions (the header row's x coordinates per date unit). Pixels-per-unit = `(x_unit_n - x_unit_1) / (n - 1)`.
245 2. Run `calc line` once over `start_index:row_y` per task — output `SVG_X` gives the bar's `x`. Run it again over `end_index:row_y` — output `SVG_X` gives `x + width`. Subtract for width.
246 3. Compare each task rect's `(x, width)` against the calculated start and end. Row y can be read directly (categories are not value-driven).
247
248 **Waterfall chart** — floating bars connected by running totals. Each bar's top and bottom edge correspond to two points on the same value axis (`cum_before`, `cum_after`):
249
250 1. Read the y-axis tick range and the plot area; compute running totals in category order (start with `cum[0] = base_value`, then `cum[i] = cum[i-1] + delta[i]` for increase, `cum[i-1] - delta[i]` for decrease, reset to delta for totals).
251 2. Build two virtual series: `top[i] = max(cum_before, cum_after)`, `bot[i] = min(cum_before, cum_after)`. Run `calc bar` twice on these with identical `--area`, `--bar-width`, `--value-range`. The `top` run's `Y` is the bar's `y`; `height = bot.Y - top.Y` for that index.
252 3. Compare each waterfall rect's `(x, y, width, height)` against the calculated pair. Connector lines should run from `(x + width, top_or_bot[i].Y)` to `(x_next, top_or_bot[i+1].Y)` at the matching shared cumulative value.
253 4. Total bars (full-height start/end) use `bot = 0` and the calc reduces to the standard `calc bar` recipe.
254
255 **Bubble chart / plotted 2×2 matrix** — partial calculator support:
256
257 1. Use `calc line` to verify bubble centers (`cx/cy`) from the X/Y values and axis ticks.
258 2. For `matrix_2x2`, verify that the axis midpoint matches the quadrant split. If the visible axes say only Low/High, read the explicit numeric mapping from the active §IX decision or SVG comment; without one, record `xy=manual (scale missing)` instead of inventing a range.
259 3. Verify radius only if `design_spec.md`, the Quick active-context decision, or SVG comments declare a size scale such as `radius = sqrt(value) * k` or explicit min/max radius mapping. `spec_lock.md` carries only the primary family/key reference and is not a size-scale authority.
260 4. If the size scale is missing, record `radius=manual (scale missing)` and inspect relative ordering by hand.
261
262 **Bar-of-pie / pie-of-pie** — decompose the primary and expanded views:
263
264 1. Replace the expanded tail in the primary data with one aggregate tail value, then run `calc pie` for the main pie.
265 2. For `pie_of_pie_chart`, run `calc pie` again on the tail values at the secondary center/radius. For `bar_of_pie_chart`, verify each stacked detail height as `tail_value / sum(tail_values) × detail_height` and confirm the segments fill the declared detail bar without gaps or overlap.
266 3. Verify that the aggregate tail slice equals the sum of the expanded values and that connector endpoints touch the two declared plot regions.
267
268 **Stock chart** — decompose each OHLC observation into four y-values:
269
270 1. Read the shared price-axis range and ordered date positions.
271 2. Run `calc line` for open, high, low, and close using the same plot area and ranges. For each date, the wick spans `high_y` to `low_y`; the body spans `min(open_y, close_y)` to `max(open_y, close_y)`.
272 3. Verify the body color/direction against `close >= open`, and verify that every body stays within its wick.
273
274 **Progress bar / gauge / funnel / sunburst — formula-verify** (no calc call needed):
275
276 - Progress bar: `fill_width = value / max × track_width`. Read `value`, `max`, and `track_width` from the SVG; compute and compare against the fill rect's `width`.
277 - Gauge: `needle_angle = start_angle + value / max × sweep_angle`. Read `start_angle` and `sweep_angle` from the SVG's arc path (e.g. half-circle `start_angle=-180`, `sweep_angle=180`). Compare against the needle's `transform="rotate(α ...)"` value (the most common form), or against endpoint `(cx + L·cos α, cy + L·sin α)` when the needle is drawn as an explicit line/path.
278 - Funnel: each trapezoid's `top_width = prev.bottom_width`, `bottom_width = top_width × next_value / curr_value`. Verify by walking the segments: for segment `i`, `(top_left_x, top_right_x) → bottom_x_inset = (top_width - bottom_width) / 2`. The first segment's top width comes from the design's outer frame.
279 - Sunburst: for each ring, `circumference = 2πr` and each node's arc length is `node_value / root_total × circumference`; offsets follow cumulative sibling values plus any explicitly declared separator gap. Verify that child arcs remain inside their parent span and that sibling values sum to the parent.
280 - Receipt should quote the formula and resulting value (e.g. `formula=value/max×track_width=0.92×700=644px`, or `formula=600×850/1000=510 bottom width`).
281
282 **Sankey / heatmap / treemap / word cloud — manual verification:**
283
284 - Sankey: no layout model for node stacking, link routing, or flow-width normalization. Verify that link widths are proportional to flow values and that node-side totals match (in = out).
285 - Heatmap: cell positions are a fixed grid (not value-driven); the value-to-color binning is what's data-driven. Verify that the color of each cell falls in the bin matching the cell's number, and that high/low extremes use the legend's high/low colors.
286 - Treemap: rectangle areas reflect value proportions but the recursive squarify layout has no calculator equivalent. Verify each rect's `width × height ≈ total_area × value / sum(values)` for top-level cells, and that nested cells sum to their parent.
287 - Word cloud: verify that keyword font sizes are monotonic with their declared weights (or match the declared weight bins), then inspect the final text bounds for overlap and clipping. Position is layout-driven; do not invent a coordinate formula.
288
289 ---
290
291 ## Step 3: Per-object receipt
292
293 Output one line per chart object from the Step 1 list. Include its semantic key;
294 receipt count MUST equal Step 1
295 list length — that is the gate-closing evidence. Quick does not persist these
296 lines as a generation plan or resume record.
297
298 ```
299 verify-charts: 03_market_share.svg | object=market-share | type=bar | mode=direct-calc | scale=0-100 (from ticks) | calc=ran | svg=updated
300 verify-charts: 03_market_share.svg | object=margin-trend | type=line | mode=direct-calc | scale=0-120 (from ticks) | calc=ran | svg=unchanged
301 verify-charts: 11_share_split.svg | object=share-split | type=pie | mode=direct-calc | scale=N/A | calc=ran | svg=updated | marker=added
302 verify-charts: 14_revenue_mix.svg | object=revenue-mix | type=stacked-bar | mode=decomposable-calc | scale=0-200 (from ticks) | calc=ran×3 | svg=updated
303 verify-charts: 18_market_bubbles.svg | object=market-bubbles | type=bubble | mode=partial-calc | xy=ran | radius=manual (scale missing) | svg=unchanged
304 verify-charts: 23_quarterly_progress.svg | object=quarterly-progress | type=progress | mode=formula-verify | formula=68/100×800=544px | svg=unchanged
305 verify-charts: 19_flow.svg | object=flow | type=sankey | mode=manual-verify | link widths consistent with values | svg=unchanged
306 ```
307
308 ---
309
310 ## After verification
311
312 Default continues with [`generate-pptx`](../generate-pptx.md) Step 7. Quick
313 returns to [`quick-generate`](../profiles/quick-generate.md) §4 for its one final
314 checker and direct export. Those authorities own the remaining serial commands,
315 gates, and success criteria.
316
316 lines MARKDOWN