Repository navigation
fix: correctives to the contract of standing grants — one expiry form, each thing said once, what six more reviews found, and D10 to D13 decided (greenhouse decisions/0615) - #85
Merged
Conversation
… (greenhouse decisions/0615) `expires_at` was read by whatever reads as a date. So a grant could carry a date relative to the moment of reading: another instant each time, and so another grant than the one a person signed. It was written, and then read as not honoured, for a digest that no longer matched. A day that does not exist was read as the days after it. A date with no offset was read in the zone of whichever process asked. It is now a date and time with its offset, in ISO 8601, and nothing else: the date, a `T`, the time to the second, then `Z` or the offset as hours and minutes with its sign. Anything else is refused with the sentence this contract already had. What a grant writes back is unchanged. No house holds a grant yet, because no published runtime writes one: no stored document changes its reading. Found by a second independent review of getmilpa/app-runtime#797, and reproduced in this suite before the change: 18 of 20 forms that are not that one were accepted.
…host owes it (greenhouse decisions/0615) A JSON text may say a key twice, and a reader takes the last one and says nothing of the first. For a document a person signs, that is a way to show one thing and mean another: an expiry and then none, one seat and then another. Measured on this branch: such a document was accepted, and read with no expiry. A standing grant whose text says a key twice in one object is now refused, naming the key and the object it is in — at every depth, and however the key is spelled. Two things are said in the classes and changed in nothing else. The canonical spelling does not give every value back: a host that writes a line with it reads the line back before it trusts it. And there is one reader for a new document and for one already signed: what an earlier version of this contract accepted and this one refuses is refused like text that was never a grant, so a host that keeps signed documents treats one it can no longer read as a fault of its record, never as a grant that is not there. Found by a third independent review, with execution, of this branch at 1d15c66. Decided by Rod on 2026-10-12: one release of the contract.
…is long, and a refusal says back only what is safe to read (greenhouse decisions/0615) A fourth independent review, with execution, of this branch at d7d438a: two findings of medium severity and nine of low. Each was red in this suite before it was changed; nine of the tests are the reviewer's own. A name ends where it ends. The pattern for a grant's id, for the name of an operation and for the operation a ceiling names as its inverse ended in `$`, which also matches before one last newline: a grant that said it superseded "release-line" and a newline was taken, and named no grant. The scan for a key said twice costs what the text is long. It kept each open object by a second hand, so every key copied every key said before it: 458 KB held the reader for 4.3 s, 927 KB for 28 s. It now answers the same on the reviewer's 15,000 texts, and 5 MB in 0.2 s. It also answers for any text: one that does not parse is refused before a key is read, where the scan used to walk it and never come back. The canonical order is the order of the bytes. Sorted the way PHP compares what looks like a number, seats "7" and "007" gave one grant two digests. A grant's ceiling is read as it is written, or refused: an inverse that is not the name of one operation, and an axis the lenient reader of history would change, used to be dropped or changed in silence. An expiry whose own spelling in UTC is not the one form is refused when it is read. A list written as an object with the keys "0", "1" is refused. A refusal says back what a drafter wrote as JSON spells it, in plain characters and at most a line of it: said back raw, a key could clear the line it was printed on and leave "OK: ... is in force" in its place. The id is looked at before a sentence is built around it. A standing that says nothing of the signature fails closed. The reader of a receipt says what a host owes a line it can no longer read. Two things are built as the narrowest option and wait for a person's decision: a red receipt is read open (a run that carries one argument more than the condition describes still says no), and an argument a grant fixes or leaves free is named in letters and underscores — the narrowest alphabet that refuses none of the 76 names measured on the published catalogue.
…ent is named in letters, digits and underscores (greenhouse decisions/0615) Three decisions of Rod on 2026-10-12, on what the fourth review left open. Every text a grant keeps is one line of plain text, and one that is not is refused when it is read: no line break, no tab, no other control character, none of the characters that turn or isolate the direction text is read in, no line or paragraph separator. It was the refusal that read as "OK", taken to a grant that is accepted: a condition named so that a judge's own sentence cleared the line a terminal printed it on. It holds for how an act is taken back, for the name and the statement of a condition and of the falsifier, for each seat, for the suspension a grant lifts, for the text an argument is fixed to and for the inverse a ceiling names — in a document and in a value built by hand. Measured on what the labs and the suites write in a grant: 432 texts, none refused. An argument is named in letters, digits and underscores, starting with a letter, at most 64 of them: the alphabet built before had no digits, and an argument named sha256 could not be fixed. A red receipt always counts: it is read open, as it was built. Nothing changes there but the words that called it a proposal. Saying text back in a refusal left one control character as it came — DEL, which JSON does not escape. It is written as its escape now.
…t counts from any run, and a host says its record reads whole (greenhouse decisions/0615) What a fifth review found in this branch, and three decisions of Rod on 2026-10-12 about what it left open. Decided by Rod: An argument is fixed to a value a person can read, and no other: text that is visible ASCII, single spaces inside, none around — or a whole number, or true or false. A fixed value is compared byte by byte with what a caller sends, so "strict" with a zero-width space after it was another run: the run a person read said no, and the look-alike said yes. It costs that an argument cannot be fixed to a value with an accent. A red receipt counts from any run. A "no" of that instrument on that content stops the act whatever arguments the run carried — one more, the fixed one missing or at another value, none at all — until the content is measured again by the run the condition describes. Green stays closed. Another content, or another operation, says nothing of the condition. A text a grant keeps carries nothing that is not seen. Besides controls and the direction controls: every format character, every space that is not U+0020, the variation selectors, the fillers that print as nothing, private use and unassigned places. Letters of every language, accents and punctuation are kept. The README lists exactly what is refused, as measured over every code point; nothing the lab's sixteen books hold is refused by it. Found by the review: Nothing is taken off the ends of a text. A reader that trims repairs: nine fields took a line break, a tab or a null byte at either end. A text that is not as it reads is refused, in all seventeen places a grant holds one — and so is the name of an operation with a separator at either end, which its identity took off the same way. What the judge says is bounded and plain. A condition, a falsifier and the content are named as JSON spells them, at most a line; a sentence the host hands in is repeated as it came when it is one line of plain text, up to 480 characters, and spelled out otherwise. The effect profile's refusals say back what they quote the same way. One place the review did not list: the name of an operation is plain by its own pattern and has no length of its own — a hundred thousand letters are one name — so a sentence says at most a line of it too. A line whose "by" names no operation is not a receipt. And a host now says its record of a grant reads whole (GrantStanding::$recordFault), or the judge refuses: skipping a line that cannot be read was the easy thing to do, and a red receipt skipped leaves the green before it speaking. Where the grant stands has no default any more. A text longer than 256 KB is refused before it is read, and one scan of the text says both a key said twice and a list written as an object. Scopes, rules and the parts of a certificate are sorted by their bytes wherever a digest depends on the order. A grant built in code is held to what a grant read from its text is held to: its inverse, its texts and its expiry. An inverse is the name of one operation under any ceiling. Three expectations this suite pinned change, by decision: a no-break space, a soft hyphen and a zero-width joiner were taken; what is blank around a text or a name was trimmed off; and a red receipt from a run in another mode than the one a condition fixes did not count.
…t a grant keeps (greenhouse decisions/0615) Decided by Rod on 2026-10-12, as part of "what is not seen is refused": the rule is said by the property, not by a list. No code point of Unicode's Default_Ignorable_Code_Point set is taken. Two of that set were still taken — the Khmer inherent vowels, U+17B4 and U+17B5, the only two of it this reader read as text. They are refused now. A test asks every code point there is, through the reader, with the Unicode tables of the PCRE the suite runs on as a second instrument: a character added to that set turns it red the day the tables know it. Of the 1,112,064 code points, 957,522 are refused. The pattern names the two by code point and not the property by its name: a PCRE older than 10.40 does not know that name, and a pattern that does not compile refuses every text there is.
…, and a record that does not read whole lends to no seat (greenhouse decisions/0615) What a sixth review found in this branch: one finding of medium severity and five of low. Two of the low ones are built as proposals, not decided. A stop that can no longer be read was not walked around by one grant — and was by two. Among several grants that name a call, the one whose record does not read whole was refused alone, and the call passed under another: the line that cannot be read may be the one that stopped it. It refuses the call now whatever another grant would lend, as a suspension does. And the other half of it: a document a host kept and can no longer read is no grant it can hand in, so there was nowhere to say it. among() asks a third thing, with no default: whether everything the host keeps of standing grants reads. When it does not, nothing is lent to any seat, whatever grants were handed in. The judge no longer skips what is not a receipt. A list built by mapping the reader over the lines holds a null for a line that cannot be read; the judge went on, with a warning of PHP, on the green before it. It refuses. Nothing is trimmed from the two digests of a receipt either: a subject with a line break after it was another text, and a red receipt spelled that way said nothing of the content it measured. An argument is not fixed to the empty text, which is no character at all. Four more fillers that are blank by their own definition are refused: U+13441, U+13442, U+16FE4, U+1D159. And where the PCRE knows Unicode's property for "shown as nothing" by name, the pattern names it beside the list, so that a character added to that set is refused the day a house runs on tables that know it. PROPOSED, NOT DECIDED — each a small change that can be taken out: A text does not begin with a combining mark, and carries no more than eight in a row. Three hundred marks on one letter are drawn over the lines around it; ordinary writing stacks at most four or five. What a person signs spells a plain character plainly: a \u escape that names a printable ASCII character other than the quote and the backslash is refused. An operation written entirely in escapes was shown as escapes and read as its name, with the digest of the plain text. Two expectations this suite pinned change: the empty text was a value an argument could be fixed to; and a key was "spelled two ways" with an escape of a plain letter, which the second proposal refuses first — it is spelled with a letter a writer does escape now, and holds either way.
…ables (greenhouse decisions/0615) The test that four fillers are refused had a control beside it: their neighbours draw something, and are text. Two of those neighbours are hieroglyphs as new as the fillers themselves (Unicode 15). The checks of this repository run on a PCRE whose tables are older: for it those two places are not assigned yet, and a text that carries one is refused — as the contract says a host with older tables does. The control uses characters of the same scripts that every table has had for many versions. Nothing in src/ changes.
…and a name is given as text, never as an identity built elsewhere (greenhouse decisions/0615) What a seventh review found in this branch: one finding of medium severity, which is a question for whoever decides, and two of low. A line that was not read, found in the list of receipts, refused its own grant and nobody else's. The judge said of a grant that what the house keeps of it does not read whole, and among several grants the call passed under another. It stops the others now, as a fault the host says does — asked of the list, not of the reason the grant was refused for: a signature that does not hold is said first, and would hide it. A name is given as text. An identity built elsewhere has already had its ends taken off, and nothing can ask for them back: a named call and a receipt could be built from one where the same text was refused. They are built from the text now, and so is a call, which took any text as its operation. PROPOSED, NOT DECIDED — each a small change that can be taken out: Under doubt, a stop stops. "The grant names the call" was made for lending, where being exact fails closed; it also decided which calls a stop reaches, and there being exact fails open. A stopped grant fixes an argument, a wider grant is in force, and the seat calls without that argument: the stopped grant "does not name" the call and the wider one lends it. With the proposal a stopped grant that lends to the seat and covers the operation refuses a call another grant would lend, unless the call says another value for something that entry fixes. Not another: the argument is not there, or is null; a number and the text of its digits; a boolean and the texts PHP and JSON write it as. Capitals, a space around a value and words for yes and no are not set aside. This is older than this branch: the published version has it. The proposal about escapes is narrowed, and its sentence corrected. It said no writer makes such an escape; writers that are safe for HTML do — the apostrophe, the angle brackets, the ampersand — and their documents were refused. It refuses now only the escape of what names are made of: letters, digits, the colon, the dot, the underscore, the dash and the space. The strict alternative is written beside it for whoever decides. The proposal about combining marks is as it was. One mutant is gone: the anchor of the pattern for an operation can no longer be reached by any input, now that a name is compared with its identity before the pattern is asked.
…ext for every caller, and a text is read only if its own spelling is — and the reach of a stop is proposed from the closed side (greenhouse decisions/0615) What an eighth review found in this branch: one finding of medium severity, which is the same question for whoever decides, and four of low. FIXED A stop beside a call named a way out that did not lead out. When the stop was a record that does not read, the refusal asked for a grant that supersedes the stopped one by name; a person gave it, and the same refusal came back. The way out is said by the kind of stop now: a record is out of the way when it reads again. The same held one line above, for a grant that names the call, suspended, whose record does not read either: it is told the same. And the README says that expired, revoked and superseded grants stop nobody when their record reads. A name is given as text for every caller. `strict_types` belongs to the caller's file: from PHP's default mode an OperationId, being Stringable, turned itself into text before the constructor looked. A named call, a receipt, a call and `named()` take anything and throw a TypeError for what is not a text. A text is read only if its own canonical spelling is. That spelling says `supersedes`, `lifts` and `expires_at` also when the text left them out, so a text 48 bytes under the limit was read and its spelling refused. PROPOSED, NOT DECIDED — each a change that can be taken out Under doubt, a stop stops — rebuilt. It listed what does not say another value, and the review found 146 of 355 spellings still walking around a stop: listing what PHP reads as one value never ends. The rule is said from the closed side now. A stopped grant that lends to the seat and covers the operation refuses the call, unless the call says beyond doubt another value for something that entry fixes: a value of the same kind as the fixed one, written the way a grant can fix it, and different. Everything else is doubt. Of the same 355, 23 stay open, each an operation's own reading of a value: capitals, a text PHP compares as the same number, and a zero that `?:` reads as nothing; 75 are refused that no reading takes for the fixed value. Its second half: the stop beside a call is answered whether or not another grant would lend it, where the answer used to be `null` and a host let the seat's own word decide; and `mayBeNaming()` is public, for a host to ask of a grant in force before that word decides. For lending nothing changes. `StandingCall` says what a host owes: the arguments as the operation reads them. Plain letters as escapes — adjusted. In a sentence it is as it was. Where a text is not a sentence — a seat, the expiry, the name and the value of an argument — the escape of every printable ASCII character is refused: a value made of what a sentence is forgiven was written whole in escapes. It costs a writer that escapes the plus an expiry with a positive offset; it writes the same instant with Z. Stacked marks: as it was.
…ich door answers a stop beside a call — and what were three proposals are decided (greenhouse decisions/0615) What a ninth review found in this branch. It passed: no finding of high or medium severity, three of low. What a run answered is asked for its type by the contract, as a name is. `ok` was typed `bool` in the signature, and `strict_types` belongs to the caller's file: from PHP's default mode the text "false" — or "no", "failed", the number 2 — built a GREEN receipt, and the call passed on it. A no that was said was kept as a yes. The constructor takes anything now and throws a TypeError for what is not a boolean. Its sibling: the inverse a ceiling names was taken from an identity built elsewhere, from such a caller. An effect profile asks whether its rollback contract is a text; it is the one change outside src/Standing, and every caller in the family hands it a text already. The words say which of the two doors answers a stop beside a call. For one stopped grant whose fixed argument the call leaves out, `among()` refuses and `judge()` says «not named», while the docblock of `among()` said it adds no criterion. `judge()` is unchanged. Its docblock, the one of `among()`, the verdict's and the first example of the README now say that a stop beside is `among()`'s to answer, and that a host asks `among()` also when it holds one grant, with every grant that lends to the seat and covers the operation. And a stop of the record beside the call is filed under the signature check, as every fault of a record is. Two sentences of the README say what is so. The cost of a stop: a call is refused unless it says another value for one thing each entry of the stopped grant over the operation fixes — not «each fixed argument». And the grants that are gone: revoked and superseded ones whose record reads stop nobody; one past its own date stops nobody unless it is still suspended. That behaviour is not changed here. DECIDED BY ROD, 2026-10-12 — D10 to D13. What were three proposals are rules, and no behaviour changes with it: the source, the README and the tests say «decided» where they said «proposed». D10. The reach of a stop: under doubt, a stop stops. Only a call that says, beyond doubt, another value for something the stopped grant fixes is outside it — of the same kind, in a grant's own spelling, and different. `among()` answers the stop whether or not another grant would lend, and `mayBeNaming()` is the host's to ask. Decided with its limit said — an operation's own reading of a value is not reached, and no rule that compares values closes it — and with its cost. A stop over the whole operation, and a stop exact by spelling as published, were not taken. D11. A text that begins with a combining mark, or carries more than eight in a row, is refused. D12. In a sentence the escape of what names are made of is refused; inside `arguments`, inside `to` and in `expires_at`, the escape of every printable ASCII character. D13. The grants that are gone, as they are: one past its own date that is still suspended keeps stopping until a new grant names it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Correctives to the contract of standing grants published as 0.30.0 and 0.30.1 (greenhouse
decisions/0615), in one release. Eleven commits, one per round that asked for them and one for a test:expires_atis read in one form and no other (second review of the host).Default_Ignorableis taken. Two still were.src/changes. Commit 7 was red in this repository's checks for it, and the reason is a fact worth having: see "What D9 depends on".Release order — read this before releasing anything else
This release refuses documents that 0.30.0 and 0.30.1 accepted, and it changes what a host has to say. Of the texts both read, each has the digest it had — except a grant whose seats, or a host line whose keys, look like numbers, whose canonical order is now the order of their bytes.
It has to be published BEFORE any host that reads a book of standing grants, and such a host has to require it. There is one reader for a new document and for one already signed, so a document an earlier version took and this one refuses is refused like text that was never a grant; a host treats that as a fault of its record.
GrantStandingno longer answers "yes" for a host that says nothing.statehas no default, andrecordFaultdefaults to "nobody checked": a host built against 0.30.1 lends nothing until it says both.StandingJudge::among()asks a third thing, with no default: whether everything the host keeps of standing grants reads; its answer may carry no grant. And a named call, a receipt and a call are built from the name of an operation as text, never from anOperationIdmade elsewhere. No published host builds any of these: milpa/app-runtime 0.220.2 has no judge.The ninth review PASSED on
d5a62fa— receipt PASS, 0 high, 0 medium, 3 lowd5a62fais the first head to pass since1d15c66: 0 high, 0 medium, 3 low (fixed in commit 11, below). By execution, in the reviewer's words: every DECIDED rule does exactly what was decided; the eighth review's M1 and L1 to L4 hold; the reach of a stop does exactly what its words say (0 deviations in 1,390 cells asked 198,770 times, and 69,984 more of two and three arguments, against an oracle that shares no code with the judge); and the head only narrows against 0.30.1 — for the reader (five corpora, 68,784 documents, none read by the head alone) and for the judge (600,000 seeded scenarios, no call lent by the head that 0.30.1 did not lend).Two judgments carry that verdict. Rod weighed them on 2026-10-12 and decided (D10, below):
==, the default?:), and 47 only under readings it did not name — a flag given as a word ("yes","on", and toifthe word"false"),(int)of a text with a tail ("7abc"), a list in one text ("beta,stable"publishes to both), a pattern, a path, percent-encoding, a bit mask, a sign. And one walk that is no reading at all: a stopped grant fixeschannelANDformat; the call says anotherformatand the samechannel, and is outside the stop. "The class has no end, and the README is right to list nothing." Only alternative (B) closes it.The reviewer also says how the stated limit is paid, and that the README is not complete there: a host can hand the judge the arguments "as the operation reads them" only for what an operation DECLARES (its schema: types and defaults) — what a handler folds, splits or casts inside is declared nowhere; and the same arguments decide LENDING, so a host that folds what the operation does not fold lends a call the grant does not name.
A, B and C on the same scenarios — the numbers Rod decided with: (A) was taken
The reviewer's 300,000 scenarios weighted towards houses in order, with (B) and (C) emulated from the head's own judge:
null, the empty text, another kind: 196 cells of the eighth review's table, not 23stopped_beside), 1,531 a red receipt from any run, 397 an instrument that changed, 5 not measured.Decided by Rod, 2026-10-12 — D10 to D13
Three rules were built by the narrow side through four rounds, waiting for him. Rod decided them after the ninth review passed, and with them the contract has no open question of design.
D10 · The reach of a stop: option (A), as it is built — under doubt, a stop stops
channeltostable; the seat calls with nochannel, with an empty one, with"stable ", or with a number where the text is fixed; the stopped grant "does not name" that call. A wider grant lent it — or no grant did, and a host let the seat's own word decide. The published 0.30.1 has it.stopped_beside). Only one thing is outside it: a call that says, beyond doubt, another value for something that entry fixes — a value of the same kind as the fixed one (text for text, a whole number for a whole number, true or false for true or false), written the way a grant can fix it (visible ASCII, single spaces inside, none around, never the empty text), and different.null, the empty text, another kind (text for a number, a number for text, a word or a number for true or false, a number with a fraction), spaces around the value, a list, an object.among()answers the stop beside the call whether or not another grant would lend it — it used to answernull, "nobody's call", where the stopped grant stood alone.StandingJudge::mayBeNaming()is public, for a host to ask of a grant IN FORCE before a seat's own word decides — otherwise the seat leaves that grant's conditions behind by leaving out the argument it fixes. What a host does with a yes is its rule; the docblock says what it owes.StandingCallsays what a host owes — the arguments as the operation READS them.tests/Standing/AProposalOfASeventhReviewTest.php(it keeps the name it had); inStandingJudge, twoifs,mayBeNaming()andsaysAnother();NamedCall::fixable().D11 · Stacked marks
A text that begins with a combining mark, or carries more than eight of them in a row, is refused. Controls: an accent written apart, Vietnamese, Thai, pointed Hebrew, Arabic with its vowels and Hindi are read.
D12 · Escapes
\uescape that names what NAMES are made of is refused: a letter, a digit, the colon, the dot, the underscore, the dash, the space. What a writer that is safe for HTML escapes — the apostrophe,<,>,&— is read.arguments(names and values), insideto, and inexpires_at, the escape of every printable ASCII character is refused: a value made of what a sentence is forgiven (*,/,<=) was written whole in escapes, shown as noise and read as the value.Z—, and one that escapes<,&, the apostrophe or the quote cannot fix an argument to a value that holds one, nor name a seat that does.tests/Standing/TwoProposalsOfASixthReviewTest.php(it keeps the name it had); inCanonical, two constants, one line, oneifandspellsWhatIsWrittenPlainly().D13 · The grants that are gone, as they are
What the ninth review found (commit 11) — each red in this suite first
The reviewer's cases are in
tests/Standing/WhatANinthReviewFoundInTheContractTest.php. Their file declared nostrict_types, on purpose; this suite's files all declare it, so the caller in PHP's default mode is reproduced through reflection, as in commit 10.okof a receipt isboolin the signature: from a file with nostrict_typesthe text"false"— or"no","failed",2— builds a GREEN receipt, and the call passes on it. The reviewer would fix this one before publishingTypeErrorfor what is not a boolean. Ond5a62fa, of twelve things that are not a boolean, seven built a green receipt, three a red one, and two were PHP's ownTypeErrorOperationIdbuilt elsewhere, from such a caller (EffectProfile::$rollbackContract, which a grant reads)EffectProfiletakes anything for its rollback contract and throwsTypeErrorfor what is neither a text nornullamong()refuses (stopped_beside) andjudge()answers "not named"; the docblock ofamong()said it "adds no criterion"judge()and ofamong(),StandingVerdict::named()and the first example of the README say that a stop beside isamong()'s to answer and that a host asksamong()also when it holds one grant. And a stop of the RECORD beside the call is filed under the signature check, as every fault of a record is — not underin_force.judge()itself is unchangedBuilt otherwise, or wider, than the line that named it — say so if it should change
src/Effect, outsidesrc/Standing.EffectProfilebelongs to the whole family, and a grant can only read the text it was given: nothing insidesrc/Standingcould ask. What it changes for the family, measured: nothing that runs — in the published family and in the host, the 13 places that give a ceiling a rollback contract hand it a text literal; the host's whole suite against this head is green, 4,636 tests, as it was againstd5a62fa. What it costs: the parameter is no longer typed?stringin the signature, so a static checker no longer flags a caller that hands it a number. If only the words should change, it is one constructor.judge()to answernamed()true for a stop beside.judge()was not to change; the test here pins what each door answers and the words that say so.in_forcefor every stop beside now expect the check of its kind, and one pinned the README's old sentence.What the eighth review found (commit 10) — each red in this suite first
The reviewer's tests are in the suite: those of L1 and L3 as they were written in
tests/Standing/WhatAnEighthReviewFoundInTheContractTest.php, and those of M1 (its eight cases) and L4 as they were written in the files of D10 and D12. The test of L2 is rewritten: theirs lived in a file that declares nostrict_types, on purpose; this suite's files all declare it, so the caller in PHP's default mode is reproduced through reflection, whose call is made in that mode whatever a file declares (checked by execution: it builds the three things onbaba41e).nullstopped_besidenames a way out that does not lead out when the stop is a record that does not read; and the README says "revoked and superseded grants stop nobody"strict_types: from PHP's default mode anOperationId, beingStringable, turns itself into textnamed()takemixedand throwTypeErrorfor what is not a textBuilt otherwise, or wider, than the line that named it — say so if it should change
"1"and1fortrue, and"0",0and""forfalse. With the rule said from the closed side nothing is listed: any value of another kind than the fixed one is doubt.TypeError, not a refusal — and now for every caller, whatever its file declares.OperationIditself is untouched for the rest of the family.NamedCall::fixable()is new and public: whether a value is one an argument can be fixed to. The rule needs to ask it of what a call carries.\u0022and\u005care refused there too.Said, not built
The zero — the text
"0"and the number0, which?:reads as nothing: the ninth review counts it inside the stated residue, and it is not built.The eighth reviewer's notes that are not counted: the reason of a suspension is a seat's own sentence in the host as it was (for the host's round); one operation covered twice under two spellings, where the wider entry makes the narrower one a decoy — the note the reviewer would act on;
matches(),covering()andnamesOperation()still take any text and trim it (lenient is the safe side for asking whether a grant governs);ok: "false"builds a green receipt from a caller in PHP's default mode;Operation::actsOnDigest()trims; a receipt'swho,argumentsandatare kept as they came.What the seventh review found (commit 9) — each red in this suite first
The reviewer's test for L1 is in
tests/Standing/WhatASeventhReviewFoundInTheContractTest.phpas written; its test for M1 is in the file of D10.judge()and stops nobody else inamong()OperationIdhanded in ready-made has already lost what stood at its ends:new NamedCall(new OperationId(" lab:scan\n"))is builtTypeError).OperationIditself is untouched for the rest of the familyStandingCalltakes any text as its operationSaid, not built — as the coordinator asked
Operation::actsOnDigest()trims the digest an operation's ownactsOnanswers; a receipt'swho,argumentsandatare kept as they came; eight marks on every letter still pass; one operation may be covered twice under two spellings. They go in the acta as not covered.What these three constructors no longer take
NamedCall::__construct(),ConditionReceipt::__construct()andStandingCall::__construct()took anOperationId(the first and the third, or a text). They take the text only. A host that built a receipt withnew OperationId($name)hands in$name. Measured: the 105 operation names three houses list at their terminal are each "one operation, as it reads".What the sixth review found (commit 7) — each red in this suite first
Four of the reviewer's tests are in
tests/Standing/WhatASixthReviewFoundInTheContractTest.phpas written, but for the third argumentamong()now asks for; its two for the marks and the escapes are in the file of D11 and D12.among()takes a third argument with no default — why the host's whole record does not read, ornull— and with a reason nothing is lent to any seat, whatever grants were handed in: the answer carries no grant and is nevernull\p{DI}, the pattern names the property beside the listrecord_unread, whatever the thing is and wherever it is in the listSaid, not built — as the coordinator asked
One operation covered twice under two spellings;
user_data:deleteanduser:data:deletebeing one operation (that isOperationId, older than this branch); the watcher, an instrument or the inverse being the covered operation;within_secondsat its maximum. They go in the acta as not covered.Built otherwise than the smallest fix named — say so if it should change
GrantStanding's declared type for the list says what is true now: anything, held to receipts by the judge.\p{DI}when the PCRE knows it, and the list is kept whole. On these tables the property changes no answer — the list alone refuses the same code points — so the one thing a test cannot show here is the property refusing a character the list does not have. A test pins that the pattern names it, and that the list alone still leaves out no code point of the set.among()returns:grantmay benull. A host that read['grant']->idhas to look first.Decided by Rod, 2026-10-12 — commits 5 and 6
!to~, single spaces inside, none around — or a whole number, or true or false. A fixed value is compared byte by byte with what a caller sends:strictwith a zero-width space after it was another run, and a green receipt from the look-alike outvoted the red one from the run a person read. Cost accepted: an argument cannot be fixed to a value with an accent or a letter of another alphabet. The class says what a host owes: it shows a fixed value to whoever signs throughCanonical::shown().Default_Ignorable_Code_Pointset is taken. Commit 5 left two of that set as text — the Khmer inherent vowels, U+17B4 and U+17B5, by its own measurement the only two. They are refused, and a test asks every code point there is, with the Unicode tables of the PCRE the suite runs on as a second instrument: a character added to that set turns it red the day the tables know it.undotexts, 17 fixed text values. Read with this head: 27 grants, 67 receipts, 58 texts. The one grant refused is the fixture of an earlier finding (an expiry in a form 0.30.1 took), and it is refused the same way on755c3ef; so is one line that is no line at all, left by the arm that nests an argument 509 levels deep. Nothing the lab uses is refused by D8, D9 or the end of trimming. Controls: the same reader refuses a lab grant once a zero-width space, a no-break space, a trailing space or a fixed value with an accent is put in it — and on755c3efit takes all four.Three tests this suite pinned change, by decision
testTextThatIsOnlyTextIsStillTaken— a no-break space, a soft hyphen and a zero-width joiner were taken; they are refused (D9). What was blank around a text was trimmed off; the text is refused (L1).testAnOperationNameEndsWhereItEnds—" lab:scan\n"was that operation; it names none now (L1).testARedReceiptSpeaksOnlyForTheConditionItsRunFitsAndTheContentItMeasured, renamed…SpeaksForItsInstrumentAndTheContentItMeasured— a red receipt from a run in another mode than the one a condition fixes did not count; it does (D5).Four more older tests changed only the words they expect: a name is said
"builds"where it was«builds», and a fixed value is refused for D8's reason.What the fifth review found (commit 5) — each red in this suite first
The reviewer's nine tests are in
tests/Standing/WhatAFifthReviewFoundInTheContractTest.phpas they were written, but for one name that ended in a space, which L1 now refuses.strict+ U+200B is accepted, and its run outvotes the run a person readtrim()took a line break, a carriage return, a tab, a vertical tab or a null byte off both ends of nine fieldsbecause,signatureFaultand the content, raw and at any lengthbynames no operation is a receipt; andnullfor an unreadable line is the easy thing to skipbyis held to the name of one operation.GrantStanding::$recordFault: a host says its record of the grant reads whole, or the judge refuses (record_unread); the default is that nobody checkedfromJson()reads; the text is decoded twicelistsAreLists()is goneOperation::instrumentDigest()and three classes ofEffect/SORT_STRINGin the seven places a digest depends on an orderstateis the one default ofGrantStandingthat still says yesrollback_contractunder a compensatable ceiling is any sentenceshown()cuts inside an escapeBuilt otherwise, or wider, than the line that named it — say so if it should be narrower
Canonical::shown()in the ten places. Eight of them — names and the content — are.because,signatureFaultand the newrecordFaultgo throughCanonical::said()instead: repeated as they came when they are one line of plain text, up to 480 characters, and spelled out byshown()otherwise. A reason names what a person has to cite to lift a stop — the digest of the suspension — andshown()cuts at 96 bytes and writes « » as escapes: the digest would be gone.shown()costs a name. A condition named with an accent is said back with its escape ("sin nombres de m\u00e1quina"). That isshown()as it was ordered: nothing a name carries can pass for this contract's own «…».Canonical::short()), in the judge and in five refusals. And the effect profile had four raw echoes, not three.:lab:publish:was kept aslab.publish. Refused now — a spelling names an operation when its identity is that same spelling. How a surface spells the inside (lab:publish,lab.publish,lab_publish, capitals) is still one operation, as it is everywhere in this family.Signaturecheck, with its own reasonrecord_unread: the seven checks stay seven.Cf, which includes a few that draw something: the Arabic number signs and their kin (U+0600–U+0605, U+06DD, U+070F, U+0890–U+0891, U+08E2) and the format controls of four historic and musical notations. Refused, as the decision says "every".What D9 depends on — measured; nothing is decided by it
8d4e307) failed there, in one test: its control said a hieroglyph next to the two blank ones «draws something, and is text», and that hieroglyph is as new as they are. For that PCRE the place is not assigned yet, and the text was refused — exactly what the paragraph above says a host with older tables does. Locally (PCRE2 10.47, Unicode 16) it was green. Commit 8 uses characters every table has had for many versions.\p{DI}is not written in the pattern: a PCRE older than 10.40 does not know that name, PHP 8.3 builds against 10.30 and later, and a pattern that does not compile refuses every text there is. The test fails, saying so, on a PCRE that cannot be asked.Decided by Rod, 2026-10-12 — commit 4, and two things commit 3 had built ahead of the decision
What the fourth review found (commit 3) — each red in this suite first
Nine of the tests are the reviewer's own, moved into
tests/Standing/WhatAFourthReviewFoundInTheContractTest.phpas they were written.$withoutD), in three patternsSORT_STRING), in the four places; the class says the order and that a float is written with the precision of its processrollback_contractthat is not text is dropped in silence: two documents, one digestCanonical::saidOnce()is public and never returns on a text that does not parsejson_validate()refuses, before a key is readCanonical::shown()), in the 19 places a refusal quotes a document; the id is looked at before a sentence is built around it. Commit 4 closes one byte commit 3 left: DEL, which JSON does not escapenullfor a line it cannot read, and its docblock said «measures nothing»new GrantStanding()says the signature holdsBuilt wider than the line that named it — say so if it should be narrower
none+guaranteedreadsnot_applicable;guaranteedby a sentence readsmanual_recovery)."budget"where they said«budget». A host that matches on the old spelling changes with it.name,statementandundo: also each seat,lifts, the text an argument is fixed to and the inverse a ceiling names. The reason is the same — a listing prints them — and none of the 432 texts measured is refused.Reproduced before it was changed
0b71e04(0.30.1): 18 of 20 forms of an expiry that are not ISO 8601 with an offset were accepted.1d15c66: a document that saysexpires_attwice was accepted and read with no expiry.d7d438a, in one run with the sources as they were pushed: 66 of the 73 tests the third commit added were red.07e302d, in one run with the sources as they were pushed: 42 of the 43 tests the fourth commit adds or changes are red.d5a62fa, in one run with the final tests as written: 61 of the 1003 tests commit 11 ends with are red — 20 of the 22 of the ninth review's file (the other 2 are its controls), and the 41 older ones whose pinned expectation changed.baba41e, in one run with the final tests as written: 95 of the 981 tests commit 10 ends with are red.NamedCall::fixable()(17) andmayBeNaming(), which was private (2).4177ab8, in one run: 36 of the 901 tests commit 9 ends with are red — the 8 of the seventh review's file, 15 of the 27 of the file of D10 (the other 12 are its controls), and 13 for the narrowed escapes. That run hands a receipt an identity in five places of the older tests, as that head asks, so that each red is red for its own assertion; as written 124 are red, most of them errors for a receipt built from a text.c7ad91f, in one run with the sources as they were pushed: 26 of the 843 tests commit 7 ends with are red — 17 of the 19 the seventh commit adds for the review, 8 of the 21 for the marks and the escapes (the other 13 are their controls), and the one older test whose expectation changes.e0bf655, in one run: the three tests commit 6 adds or widens are red — U+17B4 and U+17B5 each accepted in a text, and the test over the property naming exactly those two.755c3ef, in one run with the sources as they were pushed: 221 of the 800 tests commit 5 ends with are red — 214 of the 311 the fifth commit adds, and the 7 older ones whose expectation changes. The other 97 of the new file are controls, 90 of them ends of a text that a pattern already held.recordFault,LONGEST), so that each red is red for its own assertion. As written, 278 are red, 83 of them errors for a parameter, a constant or a method that head lacks.Measured on this head
scripts/lab/standing-grant-1194/mutants-command.json): 327, each caught, with the instrument's two controls — the 319 from before and 8 new for commit 11Default_Ignorablecode point asked each one by itself — and a mark by itself is refused for beginning the text (the rule that is now D11). Twelve mutants of the list hid behind that. It asks each between two letters now. The other two were conditions that could not be told from their absence; one is gone, and the other's mutant asks what can be told.Default_Ignorablecode point is.d5a62fa, on five reviewers' corpora (68,784 documents): commit 11 changes no line of the reading. It does not touch how a document is read. The ninth review read the same 68,784 under 0.30.1 and underd5a62fa: none read by the head alone.baba41e, on the same 40,529: commit 10 refuses 16 documents that head took, accepts none it refused, and moves no digest. 15 write, as an escape, a character of a text that is not a sentence (D12); 1 is the document whose own canonical spelling is longer than a grant is (L3).scripts/lab/standing-grant-1194/a-stop-and-a-spelling.php, two controls): a wider grant lent seven on4177ab8, five onbaba41e, and lends one on this head — capitals.4177ab8, on the three corpora there were then (24,740 documents): commit 9 changes three documents and moves no digest. The three are a sentence with an apostrophe, with<and with&written as escapes — the reviewer's own examples — which the narrowed rule reads again. Nothing else is accepted or refused otherwise. (The rule about a stop changes verdicts, not documents.)c7ad91f, on the fifth and sixth reviews' corpora (10,741 documents): commit 7 only narrows. None is accepted only now; no digest moves; 178 thatc7ad91ftook are refused — 127 for one of the four fillers, 14 for marks (D11), 26 for an escape (D12), 11 for an argument fixed to the empty text.decisions/0598) on a house of the published family with this head laid over as its archive: green.d5a62fa: its whole suite, its 240 mutants, both cattle arms (54 and 154 expectations). It already hands a receipt a strict boolean; commit 11 asks nothing new of it.Not measured
Not to be released from here.