docs(ops): the install block copied from the wrong directory, and skipped a wrapper - #762
Merged
Conversation
…pped a wrapper Reported from a real install. `launchctl bootstrap` reported `Input/output error` four times, behind four `cp: No such file or directory`. IT TOLD THE OPERATOR TO COPY FILES FROM WHERE THEY ARE NOT The block opened `cd ~/keel` and copied the plists from there. These files are authored in the DEV REPO and deployed by copying, exactly as `keel-live`'s own header says of itself -- so on a deployment that has not already been through this, which is every deployment the first time, there is nothing to copy. AND `keel-equities` HAD NEVER BEEN DEPLOYED AT ALL The equities DETECTOR runs `paper-equities-run.sh`, so nothing needed the wrapper until the console plist pointed at it. `~/keel` had `keel-live`, `keel-paper` and `keel-paperhourly` and not the fourth. A plist naming an absent program is a KeepAlive crash loop rather than a message anybody reads. `test_each_serves_its_own_deployment_through_its_own_wrapper` asserts the wrapper exists IN THIS REPOSITORY, which it always does -- the wrappers are authored here. Whether it exists in `~/keel` is what matters at runtime and no test can look: the deployment is outside the repo and differs per machine. What IS checkable is that the documented install step copies each one, so that is what the new test asserts. Also: free the ports first. An interactive `keel serve` already on 8765 is exactly the bind failure the plists' own comments describe, and it was the state of the machine that hit this. THREE WRONG TESTS BEFORE A RIGHT ONE, ALL THE SAME SHAPE The block locator matched `launchctl bootstrap` and found the DETECTOR install block earlier in the file. Anchored on `com.keel.serve` instead, it matched two blocks -- the install and the `bootout`. Both anchors together select one. Then the wrapper assertion SURVIVED deleting `keel-equities` from the loop, because the block's own comment explains why that wrapper matters and the scan could not tell prose from a command. It strips `#` comments now. Third instance this session of a scan answered by its own explanation, and the third found only by mutation. 6,412 passed / 3 skipped, ruff clean. Two mutants killed: the wrapper dropped from the loop, and the block returned to copying from the deployment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KZZxmspQXe5qJ9FAsG13s6
…me re-runnable Review of this PR's own diff. Both findings had already fired on the machine that reported the original failure, which is about as strong as evidence gets. A CAVEAT PRINTED AFTER THE COMMAND IT GUARDS IS A POST-MORTEM "Free the ports first" sat BELOW the block an operator pastes. `com.keel.serve. live` went to `last exit code = 1` with `Address already in use` three times over, because an interactive `keel serve` still held 8765 -- and the paragraph explaining exactly that was underneath. Moved above, and the check is now a command in the block rather than a sentence about one: prose cannot report which port is busy. BOOTSTRAP ON A LOADED JOB FAILS, AND SAYS NOTHING USEFUL Measured against the running `com.keel.serve.paperforward`: `launchctl bootstrap` answered `Bootstrap failed: 5: Input/output error` while the job kept running. That is the same uninformative message a first-time operator meets, so an ordinary redeploy after any change would look like a fresh breakage. `bootout` first, guarded, so the block is safe to re-run. The detector section above already draws the install / re-install distinction; this inherits it rather than restating the lesson later. Also softened the checkout path: a deployment lives at a fixed place and a source checkout lives wherever someone cloned it. AND THE ORDERING TEST ANCHORED ON PROSE It located the block by the sentence introducing it, and broke the moment that sentence was reworded in this same commit -- a test a copy edit can fail is a test about the copy. `_install_block_raw` is the verbatim block for locating and `_install_block` the comment-stripped one for asserting about commands; a stripped string does not appear in the file it came from, which is how this was found. 6,415 passed / 3 skipped, ruff clean. Four mutants killed: the warning moved back below, `bootout` removed, `bootout` placed after `bootstrap`, and the `lsof` check turned into a comment -- that last one passing only because the stripper works. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KZZxmspQXe5qJ9FAsG13s6
6 tasks
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.
Reported from a real install of #760's daemons: four
cp: No such file or directory, then fourBootstrap failed: 5: Input/output error.It told the operator to copy files from where they are not
The block opened
cd ~/keeland copied the plists from there. These files are authored in the dev repo and deployed by copying, exactly askeel-live's own header says of itself — so on a deployment that has not already been through this, which is every deployment the first time, there is nothing to copy.And
keel-equitieshad never been deployed at allThe equities detector runs
paper-equities-run.sh, so nothing needed that wrapper until the console plist pointed at it.~/keelhadkeel-live,keel-paperandkeel-paperhourly— not the fourth. A plist naming an absent program is aKeepAlivecrash loop, not a message anybody reads.test_each_serves_its_own_deployment_through_its_own_wrapperasserts the wrapper exists in this repository, which it always does — the wrappers are authored here. Whether it exists in~/keelis what matters at runtime, and no test can look: the deployment is outside the repo and differs per machine. What is checkable is that the documented install step copies each one, so that is what the new test asserts.Also added: free the ports first. An interactive
keel servealready on 8765 is precisely the bind failure the plists' own comments describe, and it was the state of the machine that hit this.Three wrong tests before a right one, all the same shape
launchctl bootstrap— and found the detector install block earlier in the file.com.keel.serveinstead, it matched two blocks: the install and thebootout. Both anchors together select one.keel-equitiesfrom the loop, because the block's own comment explains why that wrapper matters and the scan could not tell prose from a command. It strips#comments now.That is the third instance this session of a scan answered by its own explanation, and the third found only by mutation.
Checks
6,412 passed / 3 skipped, ruff clean. Two mutants killed: the wrapper dropped from the loop, and the block returned to copying from the deployment.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KZZxmspQXe5qJ9FAsG13s6