mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 01:41:21 +00:00
* fix(desktop): keep a selected folder that is named like a database log A folder the caller selected stays a selected root when its name ends in -journal or -wal. A generated log beside a database file still does not. * fix(desktop): refuse a build command that exceeds the argument vector Splitting one argument still leaves the whole command under Linux's E2BIG limit. A request past that budget is refused before the process starts. * fix(desktop): remap a captured path in an env assignment The program word stays the program. A NAME=value assignment keeps its name and follows a captured path value when that path's spelling moves. * fix(desktop): keep oversized text out of draft guards A value or line longer than the draft's text bound is not copied into a guard, so one large frame cannot fill the task by itself. * docs(desktop): correct dconf and check-preview guidance A dconf version kept without its bytes is unreadable, not an empty key list. A values preview is copied into a check only when it is an uncut scalar. * fix(desktop): keep an empty env value empty An empty assignment is not a path. Resolving it named the working directory and rewrote the value when that directory's spelling moved. * fix(desktop): keep a run's font on the run, not the frame's text A formatting attribute such as Scribus FONT is not the document's words. Joining it across runs made a frame-wide text check of ItalicBold that failed when a run was split. The font stays a value check on its own run. * fix(desktop): do not pair JSON records by a selector-shaped field A field named @record_id matched the id suffix and became [@record_id=one], which reads an XML attribute. Records paired while their pointers matched nothing. Names that start with @ or > are not id fields. * fix(desktop): count a save-numbered id once when pairing members xml:id and draw:id values such as id123456 were both generated and numbered, so the same selector was counted twice and refused. A text edit of two elements keyed only by those ids now keeps its check. * fix(desktop): count members of root JSON arrays * fix(desktop): preserve selected state directory aliases * docs(desktop): explain tool and skill refresh prerequisites * fix(desktop): align nested state selections with aliases * fix(desktop): check build runtime export capability * fix(desktop): provide complete runtime repack command * fix(desktop): retain runtime probe failures * test(desktop): identify capture independently of schema preflight * fix(desktop): preserve document URLs and value formats * fix(desktop): bound added checks and omit noisy text guards * fix(desktop): exclude unseeded locks from task checks * fix(desktop): preserve draft bounds and launch URLs * fix(desktop): render draft values using their source format * fix(desktop): preserve launch URLs and JSON draft values * fix(desktop): recognize captured file URL documents * fix(desktop): render captured file URLs for runtime home * fix(desktop): distinguish phone numbers from save metadata * fix(desktop): preserve launch URLs and user text * fix(desktop): preserve captured URLs and user text * fix(desktop): preserve local file URL authority * fix(desktop): preserve local file URL authority * fix(desktop): preserve local file URL authority * fix(desktop): render captured file URLs at launch * fix(desktop): classify numeric timestamps using field context * fix(desktop): classify numeric timestamps using field context * fix(desktop): classify numeric timestamps using field context * fix(desktop): retain context for generated draft values * fix(desktop): retain context for generated draft values * fix(desktop): retain context for generated draft values * test(desktop): cover generated IDs in text guards * test(desktop): cover generated IDs in text guards * test(desktop): cover generated IDs in text guards * fix(desktop): isolate launcher URL encoding * fix(desktop): isolate launcher URL encoding * fix(desktop): isolate launcher URL encoding * fix(desktop): isolate launcher URL encoding * fix(desktop): retain clean text in noisy record fields * fix(desktop): classify added line values in one pass * fix(desktop): apply XML quote rules to text drafts * fix(desktop): distinguish XML attributes from quoted text * fix(desktop): preserve parsed XML line context * Format appTaskChecks.ts with the pinned oxfmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(desktop): retain partial XML syntax facts * fix(desktop): recognize markdown autolinks in drafts * fix(desktop): reuse export exclusions in task drafts * docs(desktop): clarify gzip scrub limits * style(desktop): format the noisy-record draft files with the pinned oxfmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(desktop): give the root-array draft test its own describe The records describe grew past the 150-line lint limit with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(desktop): move launch execution to boundary suite * fix(desktop): redact build schema failure output * refactor(desktop): normalize schema failure once * fix(desktop): omit unsafe schema parser snippets * fix(desktop): preserve draft change and selected path evidence * test(desktop): group retained dconf note regressions * fix(desktop): respect archive entry format in draft checks * test(desktop): separate unowned-file draft note cases * fix(desktop): preserve explicitly selected journal documents * fix(xml): avoid scanning selected ancestors per tag * fix(desktop): exclude covered text runs from draft counts * fix: preserve text when drafting desktop checks * fix: restore nested desktop state aliases * refactor: share UUID recognition across draft checks * fix: retain multiline XML attribute context * fix: retain relationship identifiers in task drafts * docs: clarify desktop draft identifier handling * test(desktop): type formatting run cases as pairs * fix(desktop): carry document format into selector evaluation * test(desktop): separate markup boundary regression group * fix(desktop): propagate formats through draft selectors * fix(desktop): switch selector format within archive entries * test(desktop): remove duplicate seed filename case * test(desktop): pass JSON format in exported index parity * docs(desktop): clarify task checks before scratch export * fix(desktop): respell selected paths in file URLs * test(desktop): group captured document spelling cases * fix(desktop): bound draft preview serialization * fix(desktop): restore selected state aliases * fix(desktop): respect entry format in draft noise * test(desktop): match exported alias evidence at its JSON boundary * fix(desktop): retain app state logs in exported seeds * fix: align desktop numeric seed comparisons * test(desktop): keep one draft exclusion fixture import * test(desktop): retain log eligibility across draft test groups * style: fix desktop launch test formatting * style: format native command path schema * fix(desktop): map selected external launch paths * style(desktop): format seed document regressions * test(desktop): group launch URL regressions * fix(desktop): omit redundant nested state aliases * fix(desktop): compare added free text as a whole * fix(desktop): check recompressed seeds as shipped * docs(desktop): clarify recovered seed format * test(desktop): group shipped gzip seed checks * fix: retain quoted identifier text in task drafts * fix: recognize Unicode XML in desktop state readers * fix(desktop): bound nested draft checks * fix(desktop): explain missing arrays in truncated views * fix(desktop): find XML type references in archives * test(desktop): remove duplicated capture assertions * fix(desktop): retain nested omitted text boundaries * style(desktop): format draft value imports * test(desktop): group model and draft value checks * fix(desktop): map captured launch paths once * refactor: remove unused whole-text guard state * refactor: stop passing unused text children * test: align free-text checks with whole-note policy * fix: validate recompressed desktop archive seeds * style(desktop): format archive seed regression * fix(desktop): retain placed-item sibling guards * test(desktop): specify XML format in heap pairing fixture * fix(desktop): redact runtime schema errors * fix(desktop): normalize captured file URLs * fix(desktop): report seeded files by capture path * fix(desktop): retain startup readiness failure stage * fix(desktop): retain JSON date checks * fix(desktop): preserve archive formatting checks * fix(desktop): preserve explicitly selected journal files * fix(desktop): report build command transport limits * docs(desktop): clarify unreadable dconf versions * test(desktop): remove duplicate history regression * fix(desktop): align XML names with exported reader * fix(desktop): retain record identity in draft checks * fix(desktop): scrub XML independently of reader compatibility * style(desktop): format review fixes * style(desktop): format capture review fixes --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: morluto <76467478+morluto@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
6.8 KiB
6.8 KiB
Documents saved as zip archives
Outcome
A document an application saves as a zip archive, first FreeCAD's .FCStd,
is read into a view of its entries, so a task can check what the user did in
it. Checks name the XML elements they read by tag and attribute rather than by
position, so the same check holds across application versions that write the
document in another order, and compare numbers written as text within a
tolerance. XML that uses namespaces, as OpenDocument's content.xml and
Inkscape's SVG do, is named by the prefixes the document spells. Both
evaluators, REA's and the exported verifier's, agree.
Requirements
- Format: a file starting with a zip local file header (
PK\x03\x04) iszip, whatever its name. Its view is{entries, entry_count, truncated}: the file entries in archive order, directories left out, each{name, size, sha256, format, view, view_error}. - Reading: from the retained bytes already checked against their digest, in memory, with REA's zip reader options (CRC-32 and overlap checks, CP437 or UTF-8 names); nothing is extracted. Each entry's format and view come from the state view's own readers and limits, with the entry name in place of the file name. A SQLite or dconf database, or an archive, inside an archive is not read and says so.
- Limits: at most 1,000 entries listed (
entry_countcounts all); an entry is read only when it is unencrypted, stored or deflated, at most 16 MiB uncompressed and at most 100 times its compressed size, and while the archive has read at most 64 MiB. An entry over a limit, or whose data fails its checks, hassha256,formatandviewnull and aview_error. - Exported module:
data/getgives the same view, read with Python'szipfilefrom the file in place with the same limits, order of checks and wording; parity tests compare the two readers on the same archives. - XML names: both readers name elements and attributes as the document spells
them, prefix included (
text:p,sodipodi:docname), an element in a default namespace by its bare name (svg), and keep namespace declarations as the attributesxmlnsandxmlns:PREFIX, in document order. The exported module reads XML withexpattwice: with namespace processing, to refuse what REA's parser refuses, then without, for the names. Text splits into nodes as REA's DOM splits it: at CDATA sections, comments and processing instructions, an empty CDATA section joining the text around it. - Parsed views: a JSON or key file entry or file over the 4 MiB limit is refused before its value is built, in both readers. Its format is told apart from text by a token scan that builds no value and holds a byte per open container, which the exported reader also uses when Python's parser reaches its recursion limit, so deeply nested text is JSON only when all of it is.
- Selectors: on an array, a pointer segment
[KEY=VALUE]names the member whose string fieldKEYisVALUE,[@KEY=VALUE]the member whoseattributeshold it,[>PATH=VALUE]the member holding it one to three/-separated steps inside (in XML a descendant element's collapsed text or, endingNAME@ATTR, a child's attribute; in JSON the string at those keys), and conditions can follow one another. A selector must match exactly one member; several, or none before the last segment, fail the check with a message naming the selector. None at the last segment names no value, sovalue_absentpasses andvalue_equalsfails. - Tolerance:
value_equalstakes an optional non-negativetolerance, with a numbervalue, and passes when the value found is a number, or a decimal numeral string, at mosttolerancefrom it. - Truncation: a check decided by what a zip view leaves out depends on the
entry its pointer goes into: that entry's view missing or truncated, or the
listing truncated when the entry is not listed. A pointer whose selector
searches an array the view may hold only part of (any array of a truncated
XML view or entry view, or a cut listing) fails as undecided in both
evaluators. A check into the view of an entry without one (binary, or with a
view_error) fails in both evaluators, while checks on its metadata read; the draft checks only entries with a view, and an absence only where the entry still has one. - Changes:
valuesbetween zip versions pair array members one to one, by the first selector naming a member alone in its version and one unpaired member of the other (entries by name, XML elements by tag and attribute), even when a selector before it names nothing there, then by position; a member left unpaired is keyed by a selector naming it alone and nothing in the other version. Identity comes first: an element with identifying attributes (name,id,xid, or a prefixedidsuch asxml:id) is keyed by its tag and those alone, so one whose identifiers name nothing in the other version is added or removed; its other attributes (type,color) key only elements without one. A selector is used only when it matches one sibling, counted over every attribute of every sibling, identified ones included. Selectors are spelled only once chosen, so a long tag is not copied per attribute. A comparison is incomplete when either view leaves something out. - Draft: for a zip document, checks inside its entries' JSON, key file and XML views, through no object or array by position and no array a view may cut: an element added whole exists, one removed whole is absent, then values changed, added and removed, with an entry or a JSON value added whole checked through its members.
- Export refusals: a
tolerancewhose value is not a number. A pointer into XML that uses namespaces is accepted, in a file or an archive entry. - Reading: the exported reader reads an entry in bounded chunks, at most one byte past its declared size, so a forged small size cannot make it expand the rest of the stream.
- Directory: both readers read the central directory themselves, a record at a
time through the Zip64 end record whenever a Zip64 locator precedes the end
record, whatever the end record holds, count the file entries (directories told
apart as zip.js does: a final slash, a Unix directory mode, or the MS-DOS
attribute), and give zip.js or
zipfileonly the first 1,000 records, so memory does not grow with the number of entries.
Non-goals
- No reading of an archive inside an archive, or of a database inside one.
- No names by namespace URI: a check names the prefix the document uses, so one written for a document that binds another prefix to the same namespace does not match it.
- No other compression methods (bzip2, LZMA, Zstandard) and no encrypted entries.
- No selectors over non-string values, nested fields other than
attributes, or values holding][.