Spikes: #63 scale (linear, refuted) + #64 monospace probe round two - #79
Conversation
Prepares the #64 Keynote-bound spike so the human pass is a short scripted check rather than authoring probe slides by hand. `monospace_probe.key` is four family slides (Menlo, SF Mono, Courier New, Monaco) plus an indentation slide. Each family slide renders `iiii` / `MMMM` / `1111` at 96pt: in a genuinely monospaced face those three lines are the same width and their right edges form a clean column; under a proportional substitute `MMMM` is dramatically wider. That signal is legible at a glance, which matters because a silent substitution still renders — it just isn't monospaced. The indentation slide checks that leading-space columns hold, which is what #66 actually depends on. Registered as its own `monospaceProbe` group rather than folded into an existing one, and the findings file records how to remove it: this is spike evidence, not a permanent acceptance deck, and it should not add noise to every future human pass once the working family is pinned. Structurally green via `swift run AcceptanceDecks` (all records decode, both SIGTRAP invariants hold); `swift test` and `LINT_MODE=STRICT ./Scripts/lint.sh` pass. The render result is Leo's to record. Refs #64 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
## #63 — measured, and the concern is refuted `Sources/ScaleSpike` times `Deck.write(to:)` across a ladder of slide counts. A single 20-slide number cannot separate "quadratic but small" from "linear", so it sweeps 3/5/10/15/20 and reports the growth exponent. slides drawables median(s) 3 12 0.1049 20 80 0.6558 growth exponent 3->20: 0.97 (1 = linear, 2 = quadratic) A 20-slide demo-shaped deck writes in 0.66s and per-slide cost is flat (0.035s at 3 slides, 0.033s at 20). The quadratic SHAPE in `expandSlides` is real — `SlideCatalog` is rebuilt every loop iteration and `locate` is a full scan — but at demo scale the constant factors dominate. **#44 is not a v0.1.0 blocker.** The deck is demo-shaped rather than minimal (4 drawables/slide, transition, build) because cost scales with records per member; bare slides would understate it. Findings: `research/findings/scale_spike.md`. Still needs a human: open the kept 20-slide deck and confirm it renders. ## #64 — round one failed, but not the way it looked All four families rendered proportional AND at template default size — including Courier New, which certainly exists and is certainly monospaced. Both symptoms together rule out font substitution: a missing family would still honor the authored 96pt. Probing the archive showed KeynoteKit writes the authored values correctly — `fontName=Menlo fontSize=96.0` in a `TSWP.ParagraphStyleArchive` variation, identical for single- and multi-line boxes. So the bytes are right and Keynote ignored them. The one structural difference from `TextFormattingContent`, which does render its authored font, is paragraph count: that deck is one paragraph, every round-one probe box was three. Hypothesis: whole-item font is only honored on single-paragraph items. Round two isolates that variable — slides 1-3 hold paragraph count at one and vary family; slides 4-5 hold family and vary paragraph count and styling route. If 1-3 render and 4 does not, it is a KeynoteKit bug that blocks #66, since code blocks are inherently multi-line. Refs #63, #64 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Author update — both spikes now have results, and one of them changes the picture. #63 — measured, concern refutedAdded
Growth exponent 3→20: 0.97. Per-slide cost is flat (0.035s at 3, 0.033s at 20) — the signature of linear scaling. The quadratic shape in Still yours: open the kept 20-slide deck and confirm it renders. #64 — round one failed, but not because of monospaceYou reported the render failed. Looking at your exports: all four families rendered proportional and at template default size — including Those two symptoms together rule out font substitution. If Keynote had merely substituted an unavailable family, the authored 96pt would still have applied — you'd see large proportional text. You saw small proportional text, meaning the whole authored style was dropped. So I probed what we actually write: The archive is correct. We write the right bytes and Keynote ignored them — which makes this a KeynoteKit correctness question, not a font question. The one structural difference from Round two isolates exactly that — slides 1–3 hold paragraph count at one and vary family; slides 4–5 hold family and vary paragraph count and styling route. Deck is generated at
I've left |
Round two settles it by render. Monospace was never the problem.
slide 1 Menlo, 1 paragraph monospaced at 96pt OK
slide 4 Menlo, 3 paragraphs, item template default FAIL
slide 5 Menlo, 3 paragraphs, spans 1st + 3rd only PARTIAL
Slides 1 and 4 differ only in paragraph count — same family, same size, same
deck, same run. That is #81 (one `tableParaStyle` entry written regardless of
paragraph count), now confirmed visually as well as structurally.
Slide 5 is the useful surprise: styling each paragraph's own `Text` span
fixes the FIRST and THIRD paragraphs and leaves the SECOND proportional. So
per-span is a different off-by-one, not the same defect reappearing — and
#81's fix has to cover both routes. Its acceptance test needs at least three
paragraphs; a two-paragraph case would pass and hide this.
Consequences:
- `Menlo` is the demo deck's family and #66's `CodeTheme` default
- #66 is BLOCKED on #81 — neither styling route renders multi-line code
correctly today, so shipping it now would produce unstyled code slides
Refs #64, #81, #66
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The condensed middle line in round two looked like a second off-by-one in
the per-span route. It was not. An isolation probe:
iiii / xxxx / 1111 interior line renders Menlo — fine
MMMM / iiii / 1111 MMMM fails in FIRST position
MMMM alone still condensed, single paragraph
`MMMM` fails wherever it appears, including alone on a slide with no
multi-paragraph involvement. Any other interior line renders correctly. That
is Keynote substituting a condensed face for capital M in Menlo at 90pt —
its shrink-to-fit on a wide glyph run — not a KeynoteKit defect.
The ruler was badly chosen: I picked `MMMM` precisely BECAUSE it is the
widest glyph, which is what provokes the substitution. A width comparison
needs glyphs that do not trigger fallback.
Consequence: #81's fix is complete, and #66 is unblocked.
Refs #64, #81, #66
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Prepares the #64 Keynote-bound spike so the human pass is a short scripted check rather than authoring probe slides by hand. Does not close #64 — the render result is still yours to record.
Branches off
v0.1.xdirectly; no dependency on any other lane.What's here
MonospaceProbeContent.swift— four family slides (Menlo, SF Mono, Courier New, Monaco) + an indentation slidemonospaceProbegroup inAcceptanceDeckAcceptanceDecksCommand(the command prints the human pass, so a new deck has to add its own)research/findings/monospace_probe.md— procedure + empty results tableHow to run it
Render checklist
Slides 1–4, one per family. Each shows
iiii/MMMM/1111at 96pt.MMMMvisibly wider, ragged edges → reject that familyThis is the whole test — no measuring. A silent substitution still renders, which is exactly why the signal needs to be this blunt.
Slide 5. Leading-space indentation in Menlo; nested lines' left edges must form clean columns. If Menlo was rejected on slide 1 this slide proves nothing — re-run against whichever family survived.
Then fill in the results table in
research/findings/monospace_probe.md.Verification done here
swift run AcceptanceDecks— writes and self-checks (every record decodes, both SIGTRAP invariants hold viaUUIDMapVerifier); deck has the expected 5 slide membersswift test— all six targets passLINT_MODE=STRICT ./Scripts/lint.sh— exit 0Structural green is not a render pass; nothing here proves a font resolves.
One judgment call
I registered this in the acceptance catalog, which means it prints in every future human pass. That's noise for something that is spike evidence rather than a feature gate — but running it through
AcceptanceDecksis what gets it the structural self-check for free, and a throwaway harness wouldn't. The findings file records the cleanup: once the working family is pinned in the demo deck, drop themonospaceProbegroup and delete the content file.Refs #64
🤖 Generated with Claude Code