Compose install, re-run, update failure and the recovery of what it replaced into one acceptance run - #34
Merged
Conversation
…re it is given The installer, the failing update and the completion hook each had their own cases. None of them stated the sequence a host lives through, and the gap was load-bearing: the update cases prove the previous runtime survives every seam, but their previous runtime is a directory the fixture places on disk and selects. An installer that had lost the ability to install would leave all of them green. So one temporary destination is carried through a new install, a repeat, an update to an arriving source that fails at each of the eight seams, and the recovery of the install the run itself promoted. Because every recovery assertion is an equality that a run doing nothing also satisfies, the sequence separately requires what a no-op cannot produce: an environment in the destination, a selection naming it, and a seam that reported the boundary it stopped at against the environment it was building. The seven judgements are read where each is given rather than from whichever payload was nearest. READINGS declares the cell, its source and its path, and one read() is the only way a cell is filled; a reading that could not be made reads UNREADABLE rather than False and rather than its neighbour. The property is proved by moving one declared path at a time and requiring exactly that row to move with it, because a declaration checks only what it was written to check. Two rows could not be taken at face value. A journal count answers the same way for a directory somebody populated, so the hook row runs the Stop hook and asserts the journal goes from established absence to exactly one invocation. And nothing in the source reads model or permission state on both sides of an install: settingsPreserved answers for config bytes under a command that writes nothing, settings_usable answers whether a supplied value is admissible, and filling the preservation cell from either is the borrowed answer the rest of this refuses. That comparison is performed here and the missing cell is left recorded as missing. Redirecting --state is not isolation, so the diagnosis runs with HOME, XDG_STATE_HOME, CODEX_HOME and PATH inside the temporary directory and with a relay command named rather than discovered, and every path it reports is required to be under that root.
The procedure and the reading shape belong with the page that owns installing, updating and hooking. The host facts do not: a record that reads like a measurement nobody can reproduce is worse than an admitted gap, so the revision, the host, the interpreter and the timestamps stay in the private receipt and measuredPoints stays empty until a point is made. The page therefore states the four stages, which reading answers each of the seven and what none of them establishes, that this repository has exercised the combination only against a fixture, and how to start and recover a real one. Stopping is not on that list, because nothing here starts anything.
…othing A second review round found the same three classes as the first, each one dimension lower than it needed to be drawn, so these are the classes rather than the instances. Isolation was drawn as paths. Resolving where a component lives imports it, and the bridge smoke script starts a server, so an inherited import path had the suite running whatever this host has installed - which this work may read about and must not run. The child now gets no PYTHONPATH and no user site, and a resolved location has to be nothing or under the temporary root, so a location on the host fails the case instead of passing as a reading about somewhere else. Readable was drawn as reachable. A producer that had already refused still arrived as readable because its answer sat where the table expected one, which made the row pass a readability check on the interpreter with no TOML reader and only there. Reaching an answer and making a reading are two questions, and read() now answers the second. Independence was drawn at the accessor. Moving a value inside a payload proves this table reads the path it declared; it does not prove the command computed the values separately, and a diagnosis deriving exposure from the import result would have kept every case green. One input is now varied instead, and the answers that did not ask for it have to come back unchanged. Also: the claim is read from the install that settled it rather than first seen after a later run, and the destination is inventoried after the repeat, because the state snapshot does not count directories.
… evidence Third round, same two classes again, so these are the sets rather than a third pair of instances. Isolation had been drawn as the environment. But resolving where a component lives imports it, and the bridge smoke script starts a server, both under whatever interpreter the record names; clearing PYTHONPATH and the user site never reaches a system site directory, and checking the resolved location afterwards is too late because the import has already happened. The interpreter is the set. It is now supplied rather than discovered - a -S -E interpreter inside the destination, named by the record for every component and reached through entry points on a PATH of our own - and the assertion is on the interpreter, which is settled before any probe runs. The relay entry point is a real stand-in for the same reason: a console script that does not resolve sends the probe straight back to the fallback this exists to avoid. Independence had been drawn at the evidence. Varying an input and watching a sentence change does not exclude a verdict copied from a neighbour, because the copy would carry the neighbour's value while the evidence moved on its own. Each direction now moves a judgement: registering the bridge and observing its identity tool takes exposure from not_verified to verified, and asking for a trial takes delivery from not_applicable to not_verified. In both directions the answers that were not asked about must return identical in value and evidence. The trial flags in the procedure are written out. Naming the section that lists them was not a command anybody could run.
The exposure direction reaches a verdict by comparing the registered command, which means reading the configuration, and the supported floor has no reader for it. Asserting that verdict everywhere made the case fail on the one job it was meant to protect, and it failed for a reason that had nothing to do with independence. The delivery direction needs no reader, so it runs on both jobs and the orthogonality claim is exercised on both. Where exposure cannot rise, the case still requires it to hold still while delivery moves, and says why it cannot rise: a tool list alone must not lift a verdict that nothing was able to compare.
…hebang that runs Fourth round, and the isolation class again, so the set once more. The record governs which interpreter a probe is asked through, but a console script is run as a program and its first line governs that invocation instead - so a shebang sent back to this machine leaves every recorded path reading correctly while the survey runs outside the supplied runtime. That first line is now asserted, along with the wrapper still carrying -S -E, and the exact mutation that demonstrated the gap fails the case. Containment was string prefixes, which reads /tmp/root-escape as inside /tmp/root. It is ancestry now. Independence asserted that a verdict moved. Moving is not the claim: not_applicable becoming verified would satisfy it and mean the opposite. Both ends of each transition are named. The procedure names the relay entry point, because discovery finds whichever relay the host already has rather than the one just installed. And the two absences are written as two: no trial asked leaves delivery not_applicable, a trial asked with missing inputs leaves it not_verified naming what was missing. Also removes a helper the refactor left behind, which referenced a name that no longer existed in its scope. Verified on 3.10, 3.13 and 3.14.
…ts it A wrapper can name -S and -E in a comment and run neither, and then the flags read right while the probe had the site directory and the inherited import path the whole time. Searching the launching text for the flags was a check about a string, and the property is about a process. So the supplied interpreter is asked: it reports sys.flags.no_site and sys.flags.ignore_environment, and it is asked with an import path planted in its environment that it then has to not be able to see. A wrapper that mentions the flags without using them fails this, which is exactly what it should do.
… into it Three of the four result rows varied; the connection row never did. A cell that holds the same value in every direction cannot detect a neighbour answering with its value, and copying the import result into the connection cell passed the whole suite. The connection question has no input of its own on the command line - it is answered by what the relay says - so the direction is a relay whose doctor reports a socket it reached, taking the cell from unknown to verified while import, exposure and delivery stay where they were. The copy that survived now fails.
…them Three families said which set of admissible answers each row is checked against, and one of them was read by nothing. In a module whose entire argument is that a declared reading beats a remembered one, a declaration nothing consults is the same silence as no declaration - and a row in none of them would have been compared against nothing at all, quietly. They now have to cover the seven exactly once each, so a question added without saying how it answers fails here instead of being checked against whichever vocabulary it happened to land near.
thisisjun786
marked this pull request as ready for review
September 18, 2026 01:57
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
…its name The drift check read the producing source for the key's spelling. A literal survives in a comment, in an unrelated branch, and - for the reading this module performs itself - in this table, whose own entry is what the search would have found. A check that can be satisfied by the declaration it is checking answers its own question. The payloads are real now. The declared path is walked in the answer the source actually produced, and the case then deletes the last key and requires the row to go unreadable, so the walk is shown to be the thing the row depends on rather than a formality that happened to line up.
A review found the drift check searching the producing file for a key's spelling. It was worse than reported: EMITTING_FILES pointed the acceptance row at this very file, where the key it looked for is written in READINGS - so the check could be satisfied by its own declaration and could never establish that the producer emits anything. AGENTS.md says it directly: a text-matching test is not proof of workflow behaviour. Fixing that instance alone would have been the fourth repair of one shape, so the shape is what changed. Three places settled a question about behaviour by reading source, and two of them can ask instead. Producers are resolved as attributes of the module object and required to be callable, which is the thing a caller reaches rather than a name that also survives in a comment. Stand-ins are observed while the fixture applies them: _run calls interpose from inside the patched measurement, with every patch of that run entered, so the modules can be asked which of their attributes are not themselves - including the two pointer replacements, whose runs are made for that purpose. Declared paths are walked in payloads the sources really produced, and the row must go unreadable when its key is taken away. What cannot ask is declared and derived. A style rule about code that was never written has no object to interrogate, and the derivation that finds the others has to read this file to find them. Both are in TEXT_EVIDENCE with their reasons, and a check derives the set from this file so a new one fails here instead of arriving as another round. Also drops two constants left unused by the change, on the same grounds the module argues everywhere else: a declaration nothing reads is the same silence as none.
…t's name Three of the four result rows moved in a direction of their own; the import row moved nowhere. A review found what that leaves open, and it is the same thing the connection row left open one round earlier: a cell holding one value forever cannot catch a neighbour answering with its value, and it cannot tell a live reading from a command that quietly stopped attempting one. Both look like not_verified for good. Moving it needs a runtime that can import something, so the supplied interpreter is rebuilt to find two packages this test wrote and nothing else. It keeps -S, so no site directory of this machine is reachable, and the only import path it is given is a directory under the temporary root - the case then requires the resolved locations to be inside that root. What moved is what can be imported, not where the probe is allowed to look. All four now move, each in its own direction, so every row is checked against neighbours moving elsewhere. A diagnosis that stopped importing and answered not_verified forever fails this.
… file Two findings on the procedure, both of them the page claiming more than the commands do. The whole-file diff could never answer the question it was placed there to answer. The registration a few lines above deliberately appends a table, so the diff reports a change that is this procedure's own doing, and would report it whether or not the model and permission keys survived. It compares those keys now, through the reader the rest of the page insists on. And the block never failed an update, while sitting under a heading about the composed run - so a receipt from it could have read as covering a recovery nobody exercised. The honest repair is to say so rather than to add the missing stage: instructing an operator to break a runtime their host is using, to watch it come back, is not advice this page should give. The three stages it does not perform are named, the suite is named as where they are exercised, and the last command is marked as being for the host that arrives there having had an update fail on its own.
On the supported floor there is no tomllib, so the command exits before it reads anything and the operator has no preservation reading. Presenting it as runnable on every supported host was the page claiming more than the command does. It now names the requirement and states the outcome on 3.10 - the reading was not made, which is what the suite records there too - and says not to substitute a pattern match, for the reason the runtime gives for refusing one.
…hat do not The two rows a review found were accepting their own failure. Delivery was called with --trial alone, so the preflight refused for missing inputs and the row took not_verified as its answer. The skill link row read a Codex home where install.py had never run, so every skill was missing and the row took that, because the shape was right. An install acceptance suite that passes while nothing installed is worse than none: the next person reads that ground as covered. So there is now one run in which all seven have something that worked to read. The skills are really linked. The registration really names the command the diagnosis is asked about. Both components really import, from this checkout, through a runtime given only those two package roots. The relay really answers the doctor and every one of the eight steps a delivery makes, and the trial carries every required input including a recipient settings document the relay's own predicate accepts. The hook has really fired. Each row is then required to read its declared success answer - linked with nothing missing, verified, one invocation, preserved, verified. Two rows cannot be required to succeed on the supported floor, and they fail for one reason rather than two: exposure is settled by comparing the REGISTERED command, and preservation by reading the keys, and both live in a configuration that 3.10 has no reader for. That condition is declared with its reason and asserted where it is claimed. Then the sweep, by the answer an assertion requires rather than by its shape - the shape sweep is what missed these twice. Ten places require an answer meaning a question was not settled, and each now says why the refusal is the right answer there: four hold a BEFORE end of a transition that must finish at verified, four assert that a refusal is itself the answer (an unreadable daemon is not a stopped one, a withheld command is not an answer, a removed key must make its row unreadable, an install is never an activation), and two are the no-reader condition above. A check derives that set from this file, so a new place settling for a refusal cannot arrive unannounced. The delivery direction keeps one honest coupling rather than hiding it: a trial that completes needs a runtime with the relay in it, which is the same runtime the import row reads, so that direction compares its neighbours on their verdicts and says why it cannot compare their evidence. Docs: the preservation command names a 3.11-or-later interpreter, and says what a receipt records on the floor - the reading was not made.
The procedure ended a turn and then read hook-status, as though the number it found belonged to that turn. It does not: the journal cell reports what this hook has recorded about itself since it was installed, so on a host where it fired last week an old count reads as evidence for a callback that never happened. It reads before and after now, and the reading is the difference. The suite already established the row that way - absent, then exactly one - and the page was claiming from a single number what only a change can show.
The before/after comparison was still the wrong reading. A number that went up answers "did this hook fire at all lately", and any other session stopping inside the measurement window moves it - so the procedure could record a successful callback for a turn that never reached the hook. That is a value from one question filling another question's cell, which is the thing this whole module is built to refuse, and the previous commit repaired the symptom rather than the substitution. The records carry sessionId and turnId for exactly this reason. hook-status already names the journal it counted, so the page now reads that root and looks for the record naming the session and the turn that was ended. recordsForThisTurn is the reading: one is a callback this procedure can attribute, and zero is not a smaller number of callbacks but a turn that did not reach the hook - unreadable for this run, whatever the total says. The count is no longer offered as evidence at all. It was the one piece of the procedure somebody else could move. Run against a real firing before writing it down: one record in the journal, one for the turn, and zero when asked for a session that did not fire it.
… stands in Two findings, both of them a claim being satisfied by something other than the thing it names. The import row read verified from this checkout. component_sources put the repository's package roots on the path while the build steps are stand-ins, so the candidate held neither package and the reading reported locations in the working tree. Source being available is not the question that row asks. The real packages are copied into the candidate now - into the directory the build stand-in leaves empty, not past it - and the success case requires every resolved location to be inside the environment the run installed. A verified import that resolved anywhere else fails there. The stand-in inventory watched the wrong run. The composed lifecycle fails its update inside updating(), which replaces definition.load and definition.verify, but the sampling ran install() without that context and never saw them - so the record omitted two functions that are simulated in the run it describes, while still looking derived. The sampling now happens inside the same context, and both names are acknowledged. The second one is the more useful of the two: it is the provenance record understating what stood in for a real thing, which is the one failure that record exists to prevent.
The hook creates a record before it finishes writing it, so a journal entry being written while an operator looks would abort the decode and the callback row would read unreadable for a turn whose callback had completed. A reading that a concurrent write can overturn is not a reading of the thing it names. The snippet filters the shapes hook-status itself counts - dated directories, UUID names - and counts what it could not decode instead of stopping on it. recordsUnreadable is reported beside the match, because zero matches next to a nonzero unreadable count is not an answer either: the honest move is to look again rather than to write down a callback that did not happen or rule out one that did. Extracted from the page and run against a real firing, with a truncated record planted under a real-looking name: one record read, one unreadable, one for the turn, exit 0.
… cannot supply The block installed the runtime and never linked the skills, while the diagnosis reads that layer by running scripts/install.py --check on its own. On a Codex home nobody had linked, the link row answers that every crw-* skill is missing - an accurate reading of that home, and not a reading of the installation just made. It is the same defect the fixture had until this week, and the fixture hid it from the page: the test prepares, so the procedure could stay silent and still look covered. So the comparison was made for all seven, against what the fixture actually calls rather than against the prose. One was a missing step and it is now in the block. Three are readings of something live that no command here supplies - an App Server on the socket, a session that listed the bridge tools, a relay that can carry a delivery to a returned turn id - and those are now stated with how the operator knows they were present. Three needed nothing: the real install puts the packages in the environment, the preservation copy is already taken on both sides, and the hook step already ends a real turn. The three are not preconditions to arrange around. They are the questions, so an absent live half means the receipt records that row absent and says the rest. Carrying a row forward as though the question had been put is the one way a receipt from here misleads.
The two inventories told the reader that a new member could not arrive unannounced, and the detectors are narrower than that. One finds a call to ast.parse inside a function, so a conclusion drawn from read_text compared directly is invisible to it. The other finds a refusal spelled as a literal or as one of this module's constants inside an assert, which is a shape and not the answer an assertion requires - an aliased refusal reads as absent, and an assertNotEqual against one reads as present though it requires the opposite. A claim wider than its check is the overstatement the rest of this file spent its review rounds removing, and both docstrings were making it about themselves. They now state the reach they have: the spellings that have arrived, not the class. No detector widened and no assertion added. Widening them is a separate change, and the next person can start from a hole that is written down.
…per beside it The callback row called completion.run directly. It reached "1" whatever had happened to the registration - a broken entry point, a settings argument pointing at another file, a changed stdin or stdout contract - because none of those are on the path a helper call takes. This issue delivers an acceptance test for installation AND hook registration, so a row that skips the registration is not a residual detail; it is the claim without its subject. AGENTS.md says it plainly: source, installation and live operation are separate facts, and running the source-level helper is not evidence about an installed hook. The installer now writes the registration, the command line is read back out of the hook file it wrote rather than written out again here, and that command is executed as a program with the Stop payload on its stdin. The case also requires exactly one adapter registration, the entry point to be named in it, the settings path the install chose to be carried by it, and the process to exit silently. Breaking only the registration - the helper untouched - now leaves the journal absent, where before it still read one. Then the same question across all seven, which is a different axis from the preparation comparison: not whether a step was performed but what the reading travels. Five go through what the run installed or registered; the connection and delivery rows go through a relay this suite wrote, and those two are the rows already declared fixture and already named in the procedure as needing a live half. READING_PATHS declares each with its sentence, so a reading that moves onto a shortcut has to move a sentence too.
The success scenario reconstructed the command the fixture had already written into config.toml and handed that to diagnose. register-mcp never ran, so the row reached verified whether or not registration wrote anything - while READING_PATHS, added in the previous commit, claimed that row travels the registration this run wrote. The declaration was right about what the row should do and wrong about what it did, which is the value of having written it down. The scenario now starts with no registration at all, runs register-mcp --apply, and requires it to report CREATED before the exposure row is read. A register-mcp that reports success while writing nothing now takes mcpToolExposure to not_verified and fails the success case, where before it changed nothing.
The callback row travelled the registered command, which was the previous repair, and read it out of a second Codex home this scenario made only for the hook. So the one reading that establishes registration came from a clean hook file with no relation to the host the other six describe - the home the runtime was installed into, the skills linked into, the foreign hook seeded into. A registration that only breaks when it meets real host settings would have left the whole seven-reading run green, and a composition assembled out of two machines is not a composition. Both scenario builders now pass host.codex_home, so the installer writes the hook there, the command is read back out of that file, and the journal the row counts is that home's. The success case requires the journal root it read to be inside that Codex home, which fails now if the hook is fired anywhere else - it did not before. READING_PATHS carried only the path word; each row now names the host it reads as well, and the check requires both. The axis was half a sentence and the missing half is where this sat.
…er hands clean_store told the run its store was absent and its tables unknown while the fixture had built a populated one at the same path. Nothing failed: a run told there is no store settles that cell as established absence and moves on, so a regression that detected a store and then lost it stayed green underneath. That was the third face of one defect. A row read through a helper beside the registered command, a row read against a second Codex home, and a run told the wrong thing about its own store are all the same thing -- something handed to the code under test was not what the scenario built, and the difference was nowhere in the claim. So the difference is declared rather than repaired case by case. HANDED classifies all 77 functions defined in the module, derived by asking the module object: 8 hand the built value, 51 hand nothing of their own, 18 hand a stand-in and each of those names what the scenario has instead and what a row reading through it does not prove. INJECTIONS classifies the five switches the update fixture accepts, derived from its signature, and refuses clean_store. Three checks keep it: the inventory must match the module, no call site may hand a refused switch, and one case reads the store cells back out of a run's own result and compares them with the store the scenario built. All three go red when the switch is handed again or a function arrives unclassified. Deriving the inventory found a helper nothing called (hook_settings) and one that handed the working tree where the installed copy was available: the delivery transition now travels the packages copied into the candidate, like the success case, rather than source that was never installed. Both removed. 546 tests on 3.10, 3.13 and 3.14; validate, contracts, packages and secrets 0.
…the commands emit Three findings, one axis: a documented step that cannot run where it says it runs, or that sends an operator to a field the named command never writes. Closed by deriving both, not by patching the three lines. Absence where absence is normal. A fresh Codex home legitimately has no config.toml -- read_config treats absence as an empty configuration -- so the baseline cp failed and left nothing to compare, and the preservation row silently disappeared after a successful install and registration. The step now records the absence as its own answer, and says that a baseline that was absent makes the later reading a comparison between two absences rather than a preservation. The journal snippet gets the same treatment: hook-status on a home where the hook was never installed carries no journalRoot, which used to be a traceback where a reading belongs. Interpreters, derived rather than fixed one line at a time. Five steps in the block read a Codex configuration: install, register-mcp, both diagnose invocations and the preservation reader. Measured on 3.10 instead of inferred -- register-mcp refuses, exit 1 with outcome CONFLICT naming the interpreter and nothing written, for an absent, an empty and a populated configuration alike; install and diagnose do not refuse but report the configuration UNREADABLE, so the install still promotes and the exposure row cannot reach verified for want of a reader. register-mcp now names a 3.11-or-later interpreter like the preservation reader already did, and the three that degrade say so. Fields, derived from what each command emits. Every field-like name the section points at was checked against the real output of the command named: diagnose, hook-status and register-mcp run for real, install through the update fixture. Fifteen names -- twelve emitted by the command that is named, three produced by the section's own snippet, and one wrong: residualPaths is written only by an install failure or recovery result and never by cmd_diagnose, so an operator sent to the closing diagnose for it found nothing and read that as nothing to clear. The install result is kept with its exit code and read back for it. sessionId and turnId come from the journal records, confirmed by reading one, which is why the snippet reads records rather than a count. All three inline programs compile and were run against real output: the no-hook home, a home where the registered hook really fired, and a real failed-install result. 546 tests on 3.10, 3.13 and 3.14; validate, contracts and secrets 0.
…aming a cause Three findings from the independent review, all on the same axis as the last three: a documented step that cannot run where it says it runs, or that reports something its own reading cannot establish. The exit status went to the terminal while the result went to the receipt, so a receipt that claimed to keep the install's status did not have it. It is written to <receipt>/install.exit beside the result now. The block recommended a 3.11-or-later controller in prose and then invoked bare python3 for nine of its ten steps, so copying it on the floor degraded readings the prose said to avoid. One controller is named once at the top and used by every step. And the journal guard I added last commit committed the defect this suite exists to refuse. A missing journalRoot means the firing-journal reading could not name a usable journal, which is several states -- no registration, registrations naming different settings files, a relative spelling, settings it could not read, or journaling not configured -- and the guard reported one of them as the cause. It now reports the absence with the cell's own evidence and carries the registration and configuration cells that answer which, because choosing a cause there is the borrowed answer property one forbids. Verified by running the block's three inline programs against real output again: the no-hook home now reports firingJournal not_read, registration 0 and configuration config_absent with no cause assigned; the fired home still attributes one record to its session and turn; the failed-install reader still finds residualPaths. 546 tests on 3.14 and the CI scripts 0; no bare python3 invocation left in the block.
…ing at it The previous commit answered a cause-distinction finding by growing the guard: it carried the registration and configuration cells and said they say which state the missing journalRoot is. They narrow it and do not settle it -- an ambiguous registration and a relative settings spelling are both states in which a hook IS registered and its settings still did not resolve -- so that detail asserted a distinction the reading cannot make. Writing a distinction that does not exist is the same defect as borrowing a neighbour's answer, one layer out. So the snippet is back to the minimum: it reports the absence with the cell's own evidence, says why there is no journal is not distinguished by this reading, and stops. A paragraph after the block names the five states the absence covers, says plainly that it does not say which, points at the two cells an operator looks at next while stating that they narrow without settling, and records that telling them apart needs the command to report the cause -- a change to the command, not to this page. The 3.10 measurements are attributed rather than left to read as host facts. register- mcp and diagnose were measured against a temporary Codex home; install was measured against a temporary destination with the build steps simulated, which is the acceptance suite's arrangement and not a host. Nobody has run this block against a real host from this repository and it now says so. All three inline programs compile and run: the no-hook payload reports the absence with no cause chosen, the fired payload still attributes one record to its session and turn. 546 tests and the CI scripts 0.
Two executability findings on the procedure block. <receipt> had no creation step anywhere in the repository, so on a new acceptance run the baseline redirect failed and the install redirect stopped the install from running at all rather than merely losing a file. mkdir -p <receipt> now opens the block. And the controller assignment reads like a literal line while every other <...> in the block is a placeholder, so pasting it unsubstituted is a redirection syntax error. The convention is stated once at the top instead of being left to inference: substitute every <...> first, an unsubstituted one is a redirection rather than a value, and that is as true of the assignment as of the flags below it. Nothing here runs as it stands. Checked the way a reader would: the block extracted, its nineteen placeholders substituted, and the result accepted by both bash -n and sh -n. The three inline Python programs still compile and still run against real payloads. 546 tests and the CI scripts 0.
The diagnosis carrying the trial inputs went to a terminal and was gone. That payload is five of the seven rows plus repositoryCommit and definitionVersion -- the revision a reader needs to reproduce any of it -- so a receipt holding only the install and hook payloads could not substantiate the readings this procedure says it records. Both diagnoses are kept now, each with its exit status, and under names that tell them apart: diagnose.json is the seven-reading pass, diagnose.after-failure.json is the recovery read-back. They answer different questions and a receipt holding one of them unnamed cannot say which it holds. The reviewer named the first; the second has the same defect, so both are fixed. The receipt now carries nine files: the install result and its exit, both diagnoses and their exits, the hook status, and the configuration baseline or the record of its absence. Checked as a script again: the block extracted, its placeholders substituted, accepted by bash -n and sh -n. 546 tests and the CI scripts 0.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 27a03b652f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
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 this is
The installer, the update that fails and restores, and the completion hook each landed with their own tests. None of them states the sequence a host actually lives through, and that gap is load-bearing: the update cases prove the previous runtime survives every seam, but their "previous runtime" is a directory the fixture places on disk and selects. An installer that had lost the ability to install would leave all of them green.
This adds
scripts/ci/tests/test_install_acceptance.py, which carries one temporary destination through a new install, a repeat, an update to an arriving source that fails at each of the eight seams, and the recovery of the install the run itself promoted.Why the stage list is not the test
Every recovery assertion is an equality between two readings of the same state, and a run that did nothing satisfies all of them. So the sequence separately requires what a no-op cannot produce: an environment in the destination, a selection naming it, a settled claim from the install that made it, and a seam that reported the boundary it stopped at against the arriving environment.
The seven judgements
The criterion asks for seven and forbids one standing in for another. They span three sources, so
READINGSdeclares cell, source and path, and a singleread()is the only way a cell is filled. A reading that could not be made readsUNREADABLE— neverFalse, never the neighbour's value.Two could not be taken at face value:
settingsPreservedanswers for config bytes under a command that writes nothing;settings_usableanswers whether a supplied value is admissible. Filling the cell from either is the borrowed answer the rest of this refuses, so the comparison is performed here and the missing cell is recorded as missing.Review history worth knowing
Two review rounds found the same three classes, each drawn one dimension too low. The third commit fixes the classes, not the instances:
PYTHONPATH, no user site, and a resolved location on the host fails the caseVerification
Limits, stated rather than implied
Every row here is
fixture: a temporary destination whose build steps, relay and measurement are stand-ins inherited from the update fixture. That declaration is derived from that fixture, so a stand-in added there fails this suite until the record acknowledges it. No committed row can sayhost, and a check enforces it. This establishes nothing about an installed runtime, a live App Server or delivery on any host.Two gaps are recorded rather than closed, and are proposed as follow-ups: no runtime cell answers model/permission preservation, and no cell carries a version mismatch (
definition.verifyrefuses the install instead). On Python 3.10 there is no TOML reader, so that row readsUNREADABLEwith its reason and the test asserts the refusal; a second parser in a test is the duplicate statement the runtime declines to make. CI also runs 3.13, where the row is real.docs/runtime-install.mdgains the procedure and the reading shape. Host facts — revision, host, interpreter, timestamps — stay in the private receipt outside this repository, andmeasuredPointsstays empty until a point is made.Scope: only
scripts/ci/tests/anddocs/.packages/,skills/,.github/andscripts/crw_runtime/are untouched.