2996 Commits
Author SHA1 Message Date
aiongg 2660395db5 macOS: a Language submenu in the app menu (#1541) 2026-10-22 01:31:36 -04:00
aiongg 8a6f9725b0 IDML: test a ruler guide in a column gutter without facing pages (#1096) (#1170) 2026-10-22 01:25:12 -04:00
aiongg 496b1899a2 macOS menu bar: menus keep working after a language change; key equivalents follow the shortcuts (#1540)
* macOS menu bar: keep working after a rebuild; key equivalents follow the shortcuts in effect

* macOS menu bar: the shortcut test sets its key with window.setShortcut
2026-10-22 01:18:41 -04:00
Zuujis 438d7b6d79 Dedupe the 400-year-cycle UTC conversion and the EPUB package writer (#1537)
* Dedupe the 400-year-cycle UTC conversion and the EPUB package writer

SonarCloud flagged new-code duplication on main (17%): five copies of the
"move the instant into chrono's range by whole 400-year cycles" conversion
and two copies of the EPUB OPF/container/zip writer.

- designcraft-doc gains a `time` module: `date_parts(days)` and
  `utc_parts(secs, nanos)`. App logging, EPUB `iso8601`, PDF `civil`, PPTX
  `civil` and text-variable `civil` are now thin callers; each keeps its own
  format string and year clamp. The app reaches it through
  `designcraft_engine::doc`, so its direct chrono dependency is dropped.
- EPUB: `package_opf` + `write_package` shared by fixed-layout and
  reflowable export (same entry order and compression).
- Boundary tests on the helper: pre-1970, year 9999 -> 10000, i64 extremes,
  nanos past a second.

Output is unchanged: existing date tests pass, and fixed/reflowable EPUBs
(with/without cover, author, pre-1970 and i64::MAX dates) are byte-identical
to origin/main.

* time: drop the unreachable i128 clamp and match arms in utc_parts

Whole 400-year cycles times 400 stay under 2.6e16 for any i64 day count,
so the year can't overflow i64 and the i128 + saturate was dead code
(carried over from the copies this replaced). The date and time lookups
can't fail either; each keeps one unwrap_or_default instead of a match
with a fake 1970 fallback. Output and tests unchanged.
2026-10-21 21:46:38 -04:00
aiongg 2aa5da5950 Paragraph rules: Rule Above's offset is measured from the baseline (#1535)
* Paragraph rules: Rule Above's offset is measured from the first line's baseline

* ROADMAP: Rule Above offset progress line
2026-10-21 20:40:26 -04:00
Dylan M. Taylor 3b985e3813 Use chrono instead of hand-rolled UTC conversion (#1479)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled civil / civil_from_days / days_from_civil copies (the
146_097 / 719_468 magic numbers) across the logging timestamp, text-variable
dates, EPUB dcterms:modified, PDF metadata dates and PPTX core.xml dates with
chrono, added as a workspace dependency (default-features = false, std only, so
wasm is unaffected).

- apps/designcraft logging `timestamp` (private civil_from_days deleted).
- doc text variables: `civil` and `days_from_civil` use chrono::NaiveDate;
  `format_date` and `parse_iso_date` keep their own format/parse logic and
  still call these helpers.
- epub `iso8601`, pdf `civil`, pptx `civil`: UTC datetime via
  chrono::DateTime::from_timestamp.

Output is byte-identical and pinned by the existing date, ISO-date, EPUB,
image, EPS and logging tests. The OOXML/EPUB dcterms timestamps keep their
exact strings. Each converted helper keeps a proleptic-Gregorian fallback for
dates outside chrono's NaiveDate range (and for the serial/overflow dates
parse_iso_date can hand days_from_civil), so no input changes or panics.
AGENTS.md now says time goes through chrono.

Follow-up to storytold/cadcraft#1785

* Never panic on a clock outside chrono's range; keep 5-digit years unprefixed

logging.rs timestamp(): chrono's From<SystemTime> unwraps, so a clock past
year 262143 panicked inside the logger. Use the fallible DateTime::from_timestamp
and read such a clock, or a pre-epoch clock, as the epoch like the old saturating
code did. Years past 9999 are written with {:04} like before, because %Y adds a
'+'. Tests cover both cases.

epub iso8601(): write the year with {:04} instead of %Y, matching the old
{year:04} output, so years past 9999 are not prefixed with '+'. Test added.

AGENTS.md: the "Time goes through chrono" rule now notes the narrow fallback
for dates outside chrono::NaiveDate's range, which crates/doc/src/vars.rs
retains (Howard Hinnant's algorithm).

* Don't build an unrepresentable SystemTime in the far-future test

UNIX_EPOCH + Duration::from_secs(u64::MAX / 2) overflows Windows'
SystemTime and panicked before timestamp() ran, failing the Windows
test job. Build it with checked_add and only assert where it exists.

* Route out-of-range dates through chrono's 400-year cycle, not hand-rolled copies

doc/vars.rs kept hand-rolled Hinnant `civil_fallback`/`days_from_civil_fallback`
copies for dates outside chrono's ±262143-year range, and AGENTS.md carved a
"narrow fallback" exception for them, which left calendar arithmetic outside
chrono after all.

Replace both copies with the Gregorian 400-year cycle (146_097 days): chrono
converts the day/year within one cycle and whole cycles are added back via i128
(so i64::MIN/MAX can't overflow). `civil` is reached by the system clock through
`format_date(now(), ..)`, so it must stay exact; `days_from_civil` only ever
sees a 4-digit parsed year via `parse_iso_date`, but it uses the same cycle form
for consistency. Both reproduce the pre-chrono proleptic Gregorian result, so
outputs are unchanged (verified against the old formula over wide ranges and at
the i64 extremes).

New test pins dates past chrono's range on both sides of the epoch, through the
public `format_date` and round-tripping `days_from_civil`/`civil`, with values
from the old formula. Removed the AGENTS.md "narrow fallback" exception.

epub/pdf/pptx `civil`/`iso8601` are left as-is: the PR already dropped their
hand-rolled copies for pure chrono, and their remaining epoch (`unwrap_or_default`)
fallback only triggers for a metadata/clock timestamp past year 262143 -- the
live-clock/file-mtime case FredApps accepted, with outputs that clamp the year
anyway (pptx 0..9999, PDF DateTime). No hand-rolled copy remains there to replace.

Tested: cargo test -p designcraft-doc; fmt --check; clippy --all-targets -D warnings.

* Carry an overflowing day into the next month again in parse_iso_date

parse_iso_date accepts any day 1..=31, and the old days_from_civil
carried a day past the end of its month into the next one (2019-02-30 is
2019-03-02). from_ymd_opt rejects such a day, and unwrap_or(0) turned it
into 1970-01-01. chrono now places the 1st of the month and the day is
added on, which restores the old normalization. Tested through days_from_civil
and parse_iso_date.

* time: preserve old out-of-range date conversion (no epoch fallback)

`DateTime::from_timestamp(...).unwrap_or_default()` silently reset any
instant past chrono's year range to 1970-01-01, changing output the old
hand-rolled Howard-Hinnant code converted exactly (e.g. 10_000_000_000_000 s
was 318857-05-20 17:46:40, not the epoch). Restore the old conversion domain
with a cycle-based helper that routes the calendar through chrono (the
calendar repeats every 400 years = 146_097 days, so month/day/time come from
chrono and only the year is carried, keeping every i64 exact), then apply each
format's existing year clamp afterwards.

- apps/designcraft/src/logging.rs: `timestamp` via `utc_parts`; keep the
  pre-1970 epoch clamp; u64 secs past i64::MAX saturate, not epoch.
- crates/epub/src/lib.rs: `iso8601` via `utc_parts`.
- crates/pdf/src/export.rs: `civil` cycle-based; `date_time` keeps its
  0..=9999 year clamp.
- crates/pptx/src/package.rs: `civil` cycle-based, keeps its 0..=9999 year
  clamp on the year only (month/day/time keep the real instant).

Pinned old outputs in tests (through the public helpers):
  logging u64::MAX/2 s -> 292277026596-12-04T15:30:07.000Z (was epoch)
  epub 10_000_000_000_000 -> 318857-05-20T17:46:40Z
       -10_000_000_000_000 -> -314918-08-13T06:13:20Z
       i64::MAX -> 292277026596-12-04T15:30:07Z
       i64::MIN -> -292277022657-01-27T08:29:52Z
  pdf  civil(10_000_000_000_000) -> (318857,5,20,17,46,40)
  pptx civil(10_000_000_000_000) -> (9999,5,20,17,46,40) (year clamped)

* Don't build a year-318857 SystemTime unchecked in the logging test

Windows' SystemTime only reaches about year 30828, so
UNIX_EPOCH + Duration::from_secs(10_000_000_000_000) panicked before
timestamp() ran and failed the Windows test job. Build it with
checked_add and assert where the platform can hold it. The year-10000
case fits everywhere and stays unconditional.

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-21 19:36:27 -04:00
Dylan M. Taylor dec78db02c security: enforce HTTPS on curl downloads (SonarCloud S6506) (#1519)
Add --proto '=https' to curl invocations so redirects cannot downgrade to
plaintext HTTP. Resolves SonarCloud S6506 (shell/docker/githubactions).
2026-10-21 19:36:16 -04:00
PiMinusMaxandClaude Opus 5.5 aa1a0a73f3 Gradient panel: drag the gradient onto the Swatches panel to keep it
A gradient made in the Gradient panel stayed unnamed: there was no way
to drag it into the Swatches panel for reuse. The panel's thumbnail now
drags the selection's gradient, and the Swatches list takes the drop as
a new gradient swatch (swatch.new, "New Gradient Swatch"). A gradient
that already is a swatch is left as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:28:23 +02:00
moppeeerandClaude Opus 5.5 874d2be248 Control panel and Properties: a negative Last Line Right Indent; list buttons pressed by every paragraph
The Last Line Right Indent field takes negative values, as the First Line
Left Indent does. The Control panel's Bulleted and Numbered List buttons
show pressed through `Session::selection_has_list`, as Type › Apply Bullets
and Properties do. With #1483's fix merged, an explicit off no longer takes
the other list type away.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:20:59 +02:00
moppeeer a41ff9c609 Merge branch 'list-buttons-hanging-indent' into control-panel-lists-shading 2026-10-22 01:12:39 +02:00
moppeeerandClaude Opus 5.5 c71bf1a32c List buttons: pressed when every targeted paragraph has the list; off takes only its own
`Session::selection_has_list` checks every paragraph the list commands apply
to (selected text, cells or text frames). Type › Apply Bullets / Numbers and
Properties' Bulleted and Numbered List buttons both use it, so a selection
reaching an unbulleted paragraph isn't shown pressed. An explicit `on: false`
leaves paragraphs with the other list type, and their hanging indent, alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:12:32 +02:00
Dylan M. Taylor e2a2502fba ci: add sonar-project.properties for CI-based analysis
Marks the project ineligible for SonarCloud Automatic Analysis, resolving the
CI-vs-automatic-analysis conflict so the SonarCloud workflow succeeds.
2026-10-21 16:00:32 -04:00
Dylan M. Taylor c2dbcff51f ci: add SonarCloud scan via shared reusable workflow
Calls storytold/craft-common-actions/.github/workflows/sonarcloud.yml@main
with secrets: inherit. Adds SonarCloud badge to README where missing and
removes the redundant sonar-project.properties (config now passed by the
reusable workflow).
2026-10-21 15:46:54 -04:00
Brandon ThomasandClaude Opus 5.5 4d62a501c1 Release 0.11.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.11.0
2026-10-21 13:57:30 -04:00
Dylan M. Taylor b67232a6c8 ci: add SonarCloud scan workflow and config 2026-10-21 13:57:06 -04:00
Dylan M. Taylor 9826154db3 ci: add SonarCloud scan workflow and config 2026-10-21 13:56:26 -04:00
Hamza 0fc845750a An underline runs across a tab, as the rest of the line's text (#1466)
A tab draws nothing, so it was left out of the underline and strikethrough
bars: they stopped at the last letter before each tab and began again after it.
Forms rule their fill-in lines with underlined tabs — `Name ⇥⇥⇥⇥, city ⇥⇥⇥⇥` —
so an imported form lost every writing line, and an IDML `Underline="true"` on
a run of tabs drew nothing at all.

A tab is a character with an advance, and InDesign rules its whole width.
`PlacedGlyph::spans_rules` says which glyphs a rule runs across: the drawn
ones, and a tab or a right-indent tab that advances. The spaces a line break
trimmed off the end, the break characters and the markers' carriers are not
part of the line's text and are still skipped, so an underline stops at the
text and not at the frame edge.

Both places that draw the bars from the glyphs use it: the renderer
(`build_line`) and the PDF export (`text_rules`). The HTML and PPTX exports
mark up runs of text, which already included their tabs.

Measured on the repro in the issue, a 420×120 pt page at 2×:

  before   one underline, 63 px: the word "Name"
  now      three, 63 + 219 + 231 px: the word and both tab stretches

and the exported PDF gains the two fills for them. A tab with a leader is one
continuous bar across the leader dots to the right-aligned text after it.

Tests: the renderer's bars and the PDF export's bars for "Name<tab>City" are
one bar covering the tab's width, not two with a gap where it is. Both fail
without the change (two bars, 36→67.7 and 72→93.2, the tab's 67.7–72 unruled).
2026-10-21 20:04:12 +05:00
paaspaas00andClaude Opus 5.5 2c1973a6e4 Control panel (¶): Bulleted and Numbered List, Shading and Border, as InDesign's
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:16:25 +02:00
paaspaas00 0ff33bead8 Merge list-buttons-hanging-indent (#1483) into control-panel-lists-shading 2026-10-21 16:09:04 +02:00
paaspaas00andClaude Opus 5.5 189cccd2fc Bulleted and Numbered List buttons give InDesign's default hanging indent
The Properties buttons and Type > Bulleted & Numbered Lists > Apply Bullets /
Apply Numbers (list.bullets, list.numbers) apply the list with Left Indent
0.25 in / First Line Indent -0.25 in when the paragraph has no indents, so the
text lines up after the bullet; pressed again, the list and that indent go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:04:31 +02:00
paaspaas00andClaude Opus 5.5 8ec58cc1cc Number fields are labelled by the icon that names them (accessibility)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 14:38:28 +02:00
paaspaas00 b768ea789e Merge properties-more-options into control-panel-text-modes 2026-10-21 14:33:32 +02:00
paaspaas00andClaude Opus 5.5 4320235bc6 Space Before / Space After in the shared translation table
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 14:33:10 +02:00
paaspaas00andClaude Opus 5.5 13527f9cb7 Control panel fields: Escape reverts any typed value; parity docs for the text modes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:15:51 +02:00
Nikolai Nyegaard 5879134502 Preferences: list the languages alphabetically by their own name
- English (and Auto where offered) stays first as the source language and fallback; the rest sort by native name with accents folded, so Čeština is under C and Magyar under M; Cyrillic and CJK names follow the Latin ones
- The list used the registry order, which is the order the languages were added
2026-10-21 12:01:45 +02:00
paaspaas00andClaude Opus 5.5 6cb9466129 Docs: the Properties ••• sections in the UI parity checklist
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:57:12 +02:00
paaspaas00andClaude Opus 5.5 e177529f98 Control panel: the text controls have InDesign's Character (A) and Paragraph (¶) modes
A shows the Character Formatting Controls: font and style, size and leading, All Caps,
Superscript, Underline / Small Caps, Subscript, Strikethrough, kerning and tracking, vertical and
horizontal scale, baseline shift and skew, the character style and the language. ¶ shows the
Paragraph Formatting Controls: the nine alignments, left and first line indents, right and last
line indents, space before and after, the drop cap's lines and characters, the paragraph style,
Hyphenate and Align to Baseline Grid. The fields' icons carry their names (tooltip and
accessibility). It used to show a fixed mix of both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 10:02:03 +02:00
paaspaas00 7a970ca88c Merge remote-tracking branch 'fork/properties-more-options' into control-panel-text-modes
# Conflicts:
#	ROADMAP.md
2026-10-21 09:55:50 +02:00
paaspaas00andClaude Opus 5.5 578a1ce169 Properties: ••• expands Character and Paragraph in place, as in InDesign
Character's ••• shows vertical and horizontal scale, baseline shift, skew, language and
OpenType (the Typography panel), and the All Caps, Small Caps, Superscript, Subscript,
Underline and Strikethrough buttons. Paragraph's ••• shows the left, right, first line and last
line indents, space before and after, the drop cap's lines and characters, Align to Baseline Grid
and Hyphenate. ••• again folds the section. It used to open the Character or Paragraph panel.

The language field moves under •••, where InDesign has it. New icons for the scales, baseline
shift, skew, indents, spacing and drop caps; widgets::checkbox and ••• report their labels to
accessibility.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 09:54:22 +02:00
Dylan M. Taylor 3ce3a24f08 Merge pull request #1110 from dylanmtaylor/ci/shared-nix-workflow
ci: switch to shared nix workflow from craft-common-actions
2026-10-21 03:40:09 -04:00
skylar taylor-barrick 9f7504931d Merge pull request #1352 from FredApps/ci-xtask-ci-workflow
CI: run cargo xtask ci on pull requests and pushes to main
2026-10-20 22:40:42 -06:00
skylar taylor-barrick 63a68b3d49 Merge current main into CI workflow branch 2026-10-20 21:33:52 -06:00
skylar taylor-barrick 417ef40c4c Pin winit to storytold/winit (same commit) (#1113)
The fork moved from skylartaylor/winit to the storytold org. The pinned
revision 3d51077f is unchanged; only the repository URL differs.
2026-10-20 20:26:43 -06:00
HEOJUNFOandClaude Opus 5.5 d49343f132 Export placed greyscale TIFFs as DeviceGray (#1426)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 11:18:27 +09:00
moppeeerandClaude Opus 5.5 babb86c3ae Escape cancels a value typed over an automatic one
Typing over "(87.6 pt)" and pressing Escape leaves the leading automatic;
only Enter or leaving the field commits it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 03:54:27 +02:00
skylar taylor-barrick 1420d8c79b refactor(pdf): share placed-PDF rendering (PDFR) (#876) 2026-10-20 19:52:28 -06:00
moppeeerandClaude Opus 5.5 aa3b7b7a24 Typing the automatic leading over its value fixes it
A field showing an automatic value in parentheses commits what is typed over
it even when it is the same number, so typing 87.6 over (87.6 pt) sets fixed
leading, as InDesign does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 00:52:13 +02:00
moppeeerandClaude Opus 5.5 606b28dbec Control panel: font size, leading and tracking have a spinner and a list of values
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:30:54 +02:00
NetterSilverandClaude Haiku 5.5 e1e9923471 Keep ':', '<', '>' and '\' in Tagged Text style names
Found while testing crates/textimport/src/tagged.rs:35 (also :52)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 18:02:07 +00:00
NetterSilverandClaude Haiku 5.5 6641e7c29f Drop out-of-range RTF \uN values instead of wrapping them
Found while testing crates/textimport/src/rtf.rs:237

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 17:44:49 +00:00
Hamza ba4b6d4089 Say which backend was chosen without claiming it was the first
Two corrections to the message, both reported by CodeRabbit on #1371.

switched_from being None only means this start did not switch from a
backend that never showed a frame. A backend that failed on an earlier
start is remembered in the record, and choose() then picks the first
candidate that is not in that list -- so calling it the "first choice"
misstates how it was arrived at. The line now says either "nothing has
failed before" or which backends had, so the log says what happened.

The comment claimed that reaching this line means WGPU_BACKEND is
unset. wgpu-types returns an empty mask for an empty or unrecognised
value and begin() only returns early for a non-empty one, so such a
value reaches here with the variable set. The comment says that instead.
2026-10-20 20:59:04 +05:00
Brandon ThomasandClaude Opus 5.5 8dff7ecdb0 Skip CodeRabbit reviews on Dependabot PRs (#1386)
Adds .coderabbit.yaml so CodeRabbit no longer reviews or comments on PRs opened by dependabot[bot].

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:39:20 -04:00
Dylan M. Taylor 72f8186550 docs: add SonarCloud and CodeRabbit badges to README (#1266)
* docs: add SonarCloud and CodeRabbit badges to README

* docs: put SonarCloud and CodeRabbit badges on their own line
2026-10-20 11:33:05 -04:00
NetterSilverandClaude Haiku 5.5 c35dd44f82 Remember the Preview checkbox in Paragraph/Character Style Options
Fixes #1340

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 15:17:27 +00:00
NetterSilverandClaude Haiku 5.5 d271298362 Refuse PDF page ranges in the Place PDF dialog instead of using page 1
Fixes #1337

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 14:34:47 +00:00
NetterSilverandClaude Haiku 5.5 7aba0e15af Saturate table alternating-fill and index paragraph counts
Found while testing crates/engine/src/cmd/table.rs:1396-1403

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 14:10:59 +00:00
Hamza e572a5316f Graphics: the start-up log says which backend was chosen and how to change it
`Fallback::begin` returns before the fallback runs when `WGPU_BACKEND`
is set, logging that wgpu picks the backend. So the line below it is
reached only when the variable is *not* set -- and it said
"(WGPU_BACKEND overrides)", which reads in a log as though the user's
environment had chosen the backend when nothing had.

    before: graphics: DirectX 12 (WGPU_BACKEND overrides)
    after:  graphics: DirectX 12 (first choice; set WGPU_BACKEND to choose another)

The report quotes that line as evidence of which backend a start used,
which is exactly the wrong conclusion to be led to.

Part of #1343.
2026-10-20 18:26:44 +05:00
NetterSilverandClaude Haiku 5.5 0e7e5c3f04 Clamp polygon side count before narrowing to u32
Found while testing crates/engine/src/cmd/object.rs:710-711 (also :975)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 15:07:40 +02:00
NetterSilverandClaude Haiku 5.5 9887272efb Fix "-0p0" for tiny negative pica/cicero values
Found while testing crates/geom/src/units.rs:276

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 12:39:05 +00:00
FredAppsandClaude Opus 5.5 1fec005d19 CI: run cargo xtask ci on pull requests and pushes to main
Only path-filtered workflows run on pull requests today, so most PRs land
without a test run. Port of the wordcraft#800 workflow: Linux, standard
GitHub-hosted runner, read-only token, no secrets, craft-fonts pinned to
the release.yml commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:57:30 +02:00