Skip to content

0.5.0

Choose a tag to compare

@github-actions github-actions released this 25 Aug 21:30
· 87 commits to main since this release

Fixed

  • entity-graph's boundary test enforced nothing. An independent review of 0.4.0 added a real tokio dependency and a real std::fs::read_to_string inside escape(), and all three of the crate's own tests passed. Two holes: the scanner read the " inside a char literal as opening a string, so everything after if character == '"' was invisible — which happened to be the entire escaping function the test existed to protect; and the manifest check split on the literal [dependencies] heading, so [dependencies.tokio] was not a dependency to it.

    Both holes were ones entity-core's purity scan documents closing. The crate shipped a weaker hand-rewrite of a guard that already existed, which is the whole lesson: the scanner now lives once, in scan-support, used by both crates' tests, with the review's two plantings beside it as the proof it still works. Verified by planting both again and watching them fail.

    Writing it a third time was the obvious move and the wrong one.

  • R-95 was broken for SVG and HTML. A state name carrying a control character produced a document no XML parser and no browser accepts, from a definition entity validate had passed. XML 1.0 permits no escape for most characters below U+0020 is as invalid as the raw byte — so they are replaced with U+FFFD, which is visible in the drawing and valid in the document. Dropping them silently would make two different names draw the same box. R-95's only pin was for DOT; it now has one for each format.

  • A reference graph could silently drop an edge. Graph::references keyed its edges by display label, so a nested ref ab and a field literally named a.b collapsed into one and the second overwrote the first — hiding a dangling reference that Registry::validate_all refuses, which is the one thing that picture must never do. Array items now append [], as entity-core's own relation_targets does, and edges are collected in a list.

  • Layout and renderer disagreed about duplicate node ids — the layout took the last, the renderer the first, so an edge could leave one box and be drawn into another. Not reachable through either constructor, but Graph's fields are public. Both take the last now.

  • Two files declaring the same entity drew the same reference edge twice, with two overlaid labels.

Added

  • before and after, for ordering two instants. ISO-8601 — 2026-08-25, or 2026-08-25T12:00:00[.fff][Z], with a space accepted for the T. The clock is still read at the edge and handed in as an argument; there is no $now and there will not be, because a definition that could ask what time it is stops being replayable.

    An instant this kernel cannot read is unknown, not false — and the refusal names the operand. This is the one place the two comparison families deliberately differ: gt on two non-numbers is false because these are not numbers is an observation anybody can make, while this is not a timestamp I can read is a statement about the reader. Answering false would let after: [$args.now, $fields.due] quietly report "not yet due" for a value nobody understood.

    An explicit offset — +02:00 — is refused rather than normalised. Comparing it with a naive instant has no correct answer, and a shell that has offsets has a clock to normalise with. No date library: every one of them ships a now(), which is the thing R-01 exists to keep out.

    R-59 is new; R-53 and R-55 revised.