Skip to content

docs(ops): the install block copied from the wrong directory, and skipped a wrapper - #762

Merged
eaitbrahim merged 2 commits into
mainfrom
fix-756-install-from-repo
Sep 8, 2026
Merged

docs(ops): the install block copied from the wrong directory, and skipped a wrapper#762
eaitbrahim merged 2 commits into
mainfrom
fix-756-install-from-repo

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

Reported from a real install of #760's daemons: four cp: No such file or directory, then four Bootstrap failed: 5: Input/output error.

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 that wrapper until the console plist pointed at it. ~/keel had keel-live, keel-paper and keel-paperhourly — not the fourth. A plist naming an absent program is a KeepAlive crash loop, not 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 added: free the ports first. An interactive keel serve already 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

  1. The block locator matched launchctl bootstrap — and found the detector install block earlier in the file.
  2. Anchored on com.keel.serve instead, it matched two blocks: the install and the bootout. Both anchors together select one.
  3. 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.

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

eaitbrahim and others added 2 commits September 8, 2026 01:52
…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
@eaitbrahim
eaitbrahim merged commit 347f641 into main Sep 8, 2026
4 checks passed
@eaitbrahim
eaitbrahim deleted the fix-756-install-from-repo branch September 8, 2026 07:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant