Commit Graph
1565 Commits
Author SHA1 Message Date
skylar taylor-barrick a92010200c test(docpath): assert Unix-shaped results only on Unix
resolve_absolute_refuses_results_that_are_not_absolute resolved links against a
document at /home/u/docs/a.doc outside its cfg!(windows) branch. On Windows that
path is rooted but has no drive, so it is not absolute, resolve_absolute refuses
the result as documented, and the unwrap panicked. The Windows arm already covers
the same three cases with a drive. Found by the new docpath CI job on its first run.
2026-10-17 11:10:18 -06:00
skylar taylor-barrick 5542a9466d ci(docpath): run clippy and tests for craft-docpath on all three platforms
The per-crate workflows name their crates with -p, so the new crate had no job
and its tests, including the Windows-only colon and stream assertions, never ran
in CI.
2026-10-17 10:20:41 -06:00
skylar taylor-barrick 04e83f095a Merge pull request #166 from storytold/fix/models-provenance-for-a-running-test
craft-ai-core: record which address a test's models came from
2026-10-17 08:50:21 -06:00
skylar taylor-barrick 559992953f craft-ai-core: record which address a test's models came from
A test is not instant and the address field stays editable while it runs,
so its answer can arrive after the address has changed. `set_models` then
recorded the models against whatever the field held by the time it
returned, filing one endpoint's models under another — the mislabelling
`models_fit` exists to prevent, reached the asynchronous way rather than
the synchronous ones already closed.

`set_models` now takes the address the test was started against and
returns whether the models were taken, so an answer that outlived its
address is dropped and the caller can say the result is out of date. The
parameter replaces the old signature rather than joining it: there was no
second legitimate caller, and leaving an address-free version beside it
would have left the racy call the shorter, easier one to reach — against
this module's rule that the rules live once so two screens cannot
disagree.

Also fixes a pre-existing mismatch found while testing this:
`from_connection` recorded the loaded address untrimmed while `prepare`
compares it trimmed, so a stored endpoint with stray whitespace dropped
its models on the first save.
2026-10-16 23:07:53 -06:00
aiongg c04cc16109 fix(docpath): colons in names are refused only on Windows 2026-10-17 04:14:51 +00:00
skylar taylor-barrick 15ed713b8f Merge pull request #69 from Jeremy8776/feat/ai-model
Model provenance across loaded and preset endpoints and repeated endpoint edits, so models from one endpoint are not relabelled as another's, and eligibility resolved in both directions: a model must accept every input the tool sends, and the tool must supply every input the model requires (new ResolveError::InputRequired).

All 18 checks pass on a40245bd, including craft-ai-core fmt, clippy -D warnings, tests and the wasm32 check on Ubuntu, Windows and macOS.

Note for callers: after a tracked endpoint change, use set_models for newly discovered models; direct assignment on fresh custom drafts and unchanged saved endpoints still works. The asynchronous in-flight probe race is separate and not addressed here.
2026-10-16 21:56:16 -06:00
aiongg 0d0e5efaac feat(docpath): add resolve_absolute
resolve_absolute refuses a result that is not absolute on the running
platform, such as a relative link in a document that has no path yet.
It is the function to call before opening a file.
2026-10-17 03:36:22 +00:00
aiongg d7772fbb39 fix(docpath): refuse colons inside path components
A stored path that starts with a URL scheme and a colon is a URL; a
colon in any other name is invalid. Only a leading drive letter keeps
its colon.
2026-10-17 03:35:36 +00:00
skylar taylor-barrick a40245bd36 craft-ai-core: track model provenance by address; require the inputs a model needs 2026-10-16 20:26:06 -06:00
skylar taylor-barrick 83bf4cb25c Merge pull request #148 from midasmatterhorn/fix/r4-cms-icc-checked
cms: bound the ICC curve count before it is multiplied, and read mluc record offsets checked
2026-10-16 10:58:04 -06:00
aiongg 12281d07fe fix(docpath): accept drive hosts, legacy escapes and colon names; refuse lookalike separators 2026-10-16 16:14:16 +00:00
aiongg ddc5012437 feat(docpath): add craft-docpath for checking paths stored in documents 2026-10-16 16:01:59 +00:00
midasmatterhorn 8b71728482 cms: the mluc record is read as one checked 12-byte slice
The eager tuple computed o + 8 even when the first read had failed,
overflowing a 32-bit usize at offsets near u32::MAX (n = 2 with
size = u32::MAX - 20 reaches it: o fits, o + 8 does not). The record is
now bounds-checked in one slice and the fields read inside it, the same
complete-record pattern the profile reader uses elsewhere.
2026-10-16 14:46:23 +03:00
Jeremy 90792958fb Merge remote-tracking branch 'upstream/main' into feat/ai-model
# Conflicts:
#	Cargo.toml
#	README.md
2026-10-15 20:07:18 +01:00
Jeremy bd175be54f craft-ai-core: rename from craft-ai-model; lapse each kind of consent on its own; keep models found at a new address
Consent expiry is now per kind of data: renewing text no longer renews an expired image permission. A connection edit keeps models found by a test at the new address, and drops only the ones saved for the old one.
2026-10-15 20:06:57 +01:00
midasmatterhorn 1db56c92d2 cms: bound the ICC curve count before it is multiplied, and read mluc record offsets checked
parse_curve computed 12 + n * 2 with n straight from the file and only
checked the 1 << 20 bound afterwards, inside the table arm — on a 32-bit
(wasm32) target, which craft-cms ships branches for, a trC curve count of
0xFFFFFFFF overflows with overflow checks on and panics before the guard
could reject it. The mluc reader computed 16 + k * size unchecked, where
wrapping reads another record's bytes as the language, length and offset
(wrong text, no error) instead of stopping.

Hoist the curve-count guard above the arithmetic and compute the record
offset with checked_mul/checked_add, breaking out when it does not fit.
This ports the app-side fix accepted as PhotoCraft #4976 / PR #5227,
which was never carried into craft-cms. On a 64-bit host both sites are
benign (the arithmetic fits), so the two new tests pass before and after
there; they bite on a 32-bit/overflow-check build, which deserves a
wasm32 CI job — craft-cms has none yet.
2026-10-15 17:58:13 +03:00
midasmatterhorn 6688e05c55 cms: write_cube keeps a non-default input domain
The parser reads and validates DOMAIN_MIN/DOMAIN_MAX and the type
documents them as meaningful ('the input domain the table expects'), but
the writer never emitted them: a custom-domain .cube re-saved through
parse → write_cube came back with the default domain, passed the
domain_is_default gate that used to reject it, and every row silently
mapped colours over the wrong input range.

Emit DOMAIN_MIN/DOMAIN_MAX when the domain is not the default (parse_cube
matches keywords line by line and accepts them anywhere; {} on f32 prints
the shortest roundtripping form). Regression test:
cube_domain_survives_a_write — fails today (the written table loses the
domain), round-trips exactly with the emission.
2026-10-15 17:51:42 +03:00
midasmatterhorn 65df18d8db settings: a blanked config.toml is no longer adopted over the loaded document
A syntactically broken file keeps the loaded document and is moved aside,
but a blank file parses fine — so check_disk adopted the empty document
before its blankness test ran, and the next save wrote only the known
values: comments and unknown sections loaded at startup were deleted
silently, with no error and no backup (blank text is never written as a
backup either, so on a file's first save the content was unrecoverable).
The crate itself treats blank as untrustworthy for the backup
(recovery.rs: 'a blank or unparsable file must never replace the previous
backup') and the docs promise comments and unknown keys survive saves.

Blank text is now rejected up front, before it can replace the document.
Regression test: an_emptied_file_is_not_adopted_over_the_loaded_document
— fails today (comments and unknown sections missing after the second
save), passes with the early return; the existing backup test keeps
passing.
2026-10-15 17:49:50 +03:00
magdale76andClaude Opus 5.5 bfbf82b360 fix(print): a black and white chosen in the printer's preferences applies
The Windows job ticket always named a colour: Monochrome when the job
asked for grayscale, Color otherwise. Merged over the user's printing
preferences, that Color replaced a black and white the user had picked
in the driver's own Properties dialog, so the job came out in colour
(storytold/pdfcraft#2422).

The ticket now names a colour only when grayscale is asked for. Without
it the driver validates the ticket from the user's preferences, as the
CUPS backend and `verify_job_options` already assumed.

Checked on an HP OfficeJet 250 (PCL-3 driver) with its preferences set
to black and white: the validated ticket had psk:Color and the DEVMODE
dmColor 2 before, psk:Monochrome and dmColor 1 after. With colour
preferences it is psk:Color either way.

- `the_ticket_carries_the_job_options`: no PageOutputColor without
  grayscale (fails on the old ticket).
- `the_preferences_colour_reaches_a_job_without_grayscale` (ignored,
  needs CRAFT_PRINT_TEST_PRINTER; sends no job): the job's validated
  colour equals the preferences' colour. Fails on the old ticket with the
  queue set to black and white; passes on HP OfficeJet 250, Microsoft
  Print to PDF and OneNote.
- The Windows command preview says `color=(driver default)`, like
  `duplex=(queue default)`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 10:17:48 +02:00
Brandon ThomasandClaude Opus 5.5 3cd526ca7e CI: rustfmt the proofing language list
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 00:53:07 -04:00
c14e974285 proof: Czech (cs-CZ) spelling from the installed Hunspell dictionary (storytold/wordcraft#1048)
Same pattern as Portuguese (storytold/wordcraft#797) and Polish (storytold/wordcraft#346): the cs_CZ
dictionary is read from the system at runtime (e.g. Debian/Ubuntu
hunspell-cs), nothing is bundled. Suggestions use the dictionary's own
MAP/REP/TRY/KEY; grammar stays generic (repeated word, spacing), with
digit ratios like "3 : 1" exempt. The Czech interface now writes new
documents (and opened .txt/.md) in cs-CZ.

Engine fixes the Czech dictionary needs, also used by pl/pt:
- PFX/SFX header lines may carry a trailing comment (cs_CZ has
  "SFX y Y 80 #…"); rule lines are left literal;
- NOSUGGEST stems are accepted when typed but never offered;
- KEY is parsed for neighbour-key suggestions.

Tests use a hand-written synthetic Czech dictionary only; an
end-to-end engine test mirrors the Portuguese one.

Co-authored-by: Losminek <301412321+Losminek@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-15 00:52:43 -04:00
skylar taylor-barrickandskylartaylor 8f5a283161 ci: add comfortable runtime limits to unbounded jobs (#136)
Co-authored-by: skylartaylor <26588250+skylartaylor@users.noreply.github.com>
2026-10-15 05:15:52 +02:00
e4edea9f85 Proofing: Vietnamese text under the default English language gets no marks (storytold/wordcraft#1553)
A document typed in Vietnamese under the default editing language (en-US) was
covered in red underlines, every Vietnamese word checked as English. A
paragraph that reads as Vietnamese (words with Vietnamese-only letters: the
breve and horn letters, đ, ĩ ũ, the tone-marked vowels of Latin Extended
Additional, or stacked combining marks) is now treated like any language
without proofing tools: no spelling or grammar marks, as Word's automatic
language detection does. A Vietnamese name in English text (Nguyễn) is no
longer flagged either; French and Portuguese, which share â ê ô, are unaffected.

Automatic hyphenation also leaves Vietnamese paragraphs and words whole
(single syllables never take a hyphen); the English patterns happen not to
split these words today, and the guard keeps it so.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 23:12:46 -04:00
Justin CapellaandClaude Sonnet 5.5 18c4d3146a Accept a one-sided request on a queue whose driver has no duplex feature
The Windows path refused any explicit duplex request whose validated PrintTicket lacked the duplex feature. The Print dialog asks for one-sided by default, so every queue without a duplex unit refused with default settings, although one-sided is all such a queue can do and nothing was dropped.

A one-sided request is now satisfied when the driver's PrintCapabilities offer no duplex feature at all. Two-sided requests without the feature, a driver that offers the feature but returns a ticket without the setting, and capabilities that cannot be read are still refused. Copies, collation, colour, paper, orientation and scaling are checked as before.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 20:11:20 -07:00
skylar taylor-barrick 2c67684303 feat(pdf): share patched PDF reading and rasterization (#106)
PDFR / #106: share the patched PDF reader, interpreter and raster boundary
with explicit input and decode limits, diagnostics and portable contracts.

Preserve the original reader/writer commits and immutable consumer pins.
Fresh current-main workspace gates and all 15 hosted jobs passed on the
exact integration tree. Applications retain their own import/export policy.
2026-10-14 20:01:00 -06:00
skylar taylor-barrick 7cd7fbbbe3 fix(pdf): integrate shared reader with main
PDFR: retain the reviewed reader and writer pins while incorporating current
printing changes and the CMS test lint correction.
2026-10-14 19:45:28 -06:00
skylar taylor-barrick 6cddad4079 feat(pdf): add guarded shared PDF writing (#105)
Add opt-in shared PDF authoring with bounded font preparation, caller-owned metadata and settings, guarded serialization, and a backend that rejects poisoned drawing state.

Preserve the existing writer commits so immutable dependency pins remain reachable from main. Reader and application migrations remain separate.

PR #105.
2026-10-14 19:19:41 -06:00
3802149875 Italian proofing: po', qual è, È and un/un' grammar rules; more elisions in spelling (storytold/wordcraft#1585)
* Italian proofing: po', qual è, È and un/un' grammar rules; more elisions in spelling

- grammar (works without a dictionary): un pò / un po -> un po'; qual'è -> qual è;
  E' -> È; un'altro -> un altro and un altra -> un'altra (also nessun, ciascun,
  qualcun, alcun), gender from the ending with masculine -ista/-ma/-cida... left alone;
  more emphatic doubles allowed (pian piano, poco poco, così così...)
- spelling: more elisions (dov'è, cos'è, anch'io, senz'altro, nessun'altra, n'ha...),
  truncations po'/mo'/be' accepted, pò and qual'è left to grammar (no double marks)
- tests: rule tests, grammar proptests, Italian suggestion proptest, It in mixed-span proptest

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: credit lupant by their GitHub profile name

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 19:50:35 -04:00
488c246c75 Proofing: status bar flags a language whose dictionary isn't installed (storytold/wordcraft#1167) (storytold/wordcraft#1441)
* Proofing: status bar flags a language whose dictionary isn't installed (storytold/wordcraft#1167)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* vi: missing-dictionary status strings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 19:32:30 -04:00
neronek22andneronek22 b740615573 Improve Polish spelling suggestions for final consonant devoicing (storytold/wordcraft#1298)
Co-authored-by: neronek22 <aantoszek@gmail.com>
2026-10-14 18:17:07 -04:00
85f0a76e68 Russian proofing: spelling, suggestions, grammar and word division (storytold/wordcraft#894)
* Russian proofing: spelling, suggestions, grammar and word division

Runs tagged ru get Russian tools instead of none:
- spelling against an installed ru_RU Hunspell dictionary (not bundled;
  LibreOffice dict-ru folders searched; KOI8-R and Windows-1251 decoded),
  with ё optional, hyphenated words and solid compounds understood, не with
  adjectives, participles and verbal nouns, prefixed verbs, abbreviations
  with endings and camel case left alone, plus our supplement of modern
  words with their declensions (assets/spelling/ru-extra.txt);
- suggestions tuned for Russian: е/ё, letter groups, common confusions,
  missing spaces, typos and a stem scan;
- grammar rules with Russian messages (repeated words, spaces, sentence
  capitals with Russian abbreviations, likely missing commas before
  clause openers, doubled punctuation);
- Russian word division from the spelling rules, written as code.

* Options: Russian in the dictionaries list (ProofLang::Ru arm)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Магда М.Г. <mail@mgmagda.ru>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:21:39 -04:00
4fa0fd1847 Proofing: a Dictionaries folder setting, and the dictionary each language found (storytold/wordcraft#1063) (storytold/wordcraft#1084)
File › Options › Proofing gets a Dictionaries folder: a folder of Hunspell
.aff/.dic files searched before the system locations, saved with the settings
and applied at start-up. An app started from Finder or the Dock doesn't see
WORDCRAFT_DICTIONARIES, so this is how it finds a dictionary kept in a folder
of the user's own. Changing it reloads the Polish and Portuguese dictionaries
and checks the text again. The pane lists the dictionary file each language
found, or that none was found, so missing spelling marks are explained.

Agents set it with file.options {"dictionariesFolder": path | "auto"}; a
missing folder or a relative path is refused and changes nothing.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:25:00 -04:00
74b0eab93a proof: Turkish spelling, suggestions, grammar and hyphenation (storytold/wordcraft#1527)
* proof: Turkish spelling, suggestions, grammar and hyphenation

* Turkish: dictionary tests skip when no Turkish Hunspell dictionary is installed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:45:30 -04:00
Eduardo GarciaandClaude Sonnet 5.5 49a3a02950 fix(proof): British spellings such as honour and prioritise are not flagged (storytold/wordcraft#40) (storytold/wordcraft#1536)
The bundled Moby list already knows many British forms (judgement,
defence, programme) but still flagged others: honour and its inflections,
colourful, colourless, rigour, glamour, prioritise, privatise,
synthesise, paediatric and a few more.

Adds those base forms to assets/spelling/en-extra.txt (inflections come
from the existing rules) and a regression test. A separate en-GB
dictionary chosen from w:lang is still open on the issue.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 14:29:23 -04:00
Saad AbdullahandSaad Abdullah 54f7b5b900 fix(proof): classify each whitespace token once when checking spelling (storytold/wordcraft#1335) (storytold/wordcraft#1490)
Co-authored-by: Saad Abdullah <saadkhantareen@users.noreply.github.com>
2026-10-14 13:26:10 -04:00
Jeremy cb7f55bae4 craft-ai-model: scope consent to a capability and let it lapse
A configured connection does not authorise an app by itself. An agreement now
covers one app, connection, destination and capability, for the kinds of data
it named, and may carry an expiry (unix seconds).

- Disclosure carries the capability; ConsentRecord gains optional capability
  and expires_at.
- ConsentLedger::needs_consent takes the time (the crate has no clock);
  grant_until sets an expiry, grant stays open-ended. The latest grant sets
  the expiry for that capability only.
- Records saved before this have no capability and cover nothing, so the
  person is asked once more.

Nine new tests; six deliberate bugs (expiry ignored, off by one, capability
ignored, legacy record covers everything, expiry not updated, timed grant made
permanent) were each caught.
2026-10-14 14:21:44 +01:00
skylar taylor-barrick ca50d63b77 fix(pdf): preserve upstream reader behavior during migration 2026-10-14 02:26:18 -06:00
euisuhandOpenAI Codex 11cbf52ea7 test(settings): respect effective filesystem permissions
Probe effective write restrictions so privileged container runs do not
assert errors the OS cannot provide, while retaining unprivileged coverage.

Closes #46

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-10-14 16:03:59 +09:00
skylar taylor-barrick b4712ff5e5 fix(pdf): preserve optional shaping in the reader stack 2026-10-14 00:11:03 -06:00
skylar taylor-barrick f39922b214 fix(pdf): make backend text shaping opt-in 2026-10-14 00:01:36 -06:00
mbaksaandBrandon Thomas 95a9aaac66 Add Croatian spelling and grammar support (storytold/wordcraft#1114)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 02:00:58 -04:00
RegalDragoon200andBrandon Thomas 77e550ea0c Italian proofing: it_IT and it_CH spelling, suggestions, grammar and hyphenation (storytold/wordcraft#951) (storytold/wordcraft#1090)
* Italian proofing: it-IT spelling, suggestions and grammar (storytold/wordcraft#951)

* Italian proofing: Review Language menu and editing language

* Italian proofing: interface test for editing language

* Italian proofing: find the Swiss it_CH dictionary too

* Italian proofing: TeX hyphenation patterns (MIT option)

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 01:52:47 -04:00
skylar taylor-barrick 457a078809 Merge pull request #42: qualify native Windows printing
Validate native Windows submission and share RGB printing
2026-10-13 22:38:03 -06:00
skylartaylor 8b8576f0b0 Use fixed-size chunks in the CMS total-ink regression 2026-10-14 06:27:12 +02:00
skylartaylor 21e297f440 Merge commit '3d37da389a3618ab9b76109da11416e9ca4ea719' into codex/final-merge-native-libs-20261014-root 2026-10-14 06:16:39 +02:00
Jeremy ba6ff9187c Add craft-ai-model: the data model and contract for AI in the Craft Apps 2026-10-13 21:53:38 +01:00
skylar taylor-barrick 89dcbb3060 test(pdf): pin extraction policy and retry fixtures (PDFR) 2026-10-13 13:24:54 -06:00
skylar taylor-barrick c07b3fada6 feat(pdf): share patched reading and rasterization 2026-10-13 12:52:32 -06:00
skylar taylor-barrick c3487320b2 feat(pdf): add shared guarded writer foundation 2026-10-13 12:29:12 -06:00
skylar taylor-barrick e9546e191d Merge pull request #43 from storytold/codex/atomic-normal-permissions-20261013
craft-atomic: default to normal file permissions with explicit private writes
2026-10-12 23:38:37 -06:00