0.5.0
Fixed
-
entity-graph's boundary test enforced nothing. An independent review of 0.4.0 added a realtokiodependency and a realstd::fs::read_to_stringinsideescape(), 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 afterif 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, inscan-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 validatehad passed. XML 1.0 permits no escape for most characters belowU+0020—is as invalid as the raw byte — so they are replaced withU+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::referenceskeyed its edges by display label, so a nested refa→band a field literally nameda.bcollapsed into one and the second overwrote the first — hiding a dangling reference thatRegistry::validate_allrefuses, which is the one thing that picture must never do. Array items now append[], asentity-core's ownrelation_targetsdoes, 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
-
beforeandafter, for ordering two instants. ISO-8601 —2026-08-25, or2026-08-25T12:00:00[.fff][Z], with a space accepted for theT. The clock is still read at the edge and handed in as an argument; there is no$nowand 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, notfalse— and the refusal names the operand. This is the one place the two comparison families deliberately differ:gton two non-numbers isfalsebecause 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. Answeringfalsewould letafter: [$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 anow(), which is the thing R-01 exists to keep out.R-59 is new; R-53 and R-55 revised.