Repository navigation
Conversation
The plist's environment had only PATH and HOME, so ION_HOME never reached the scheduled run. An operator with ION_HOME set paused ion from their shell, and the 06:30 run read ~/.ion: another state DB and a kill switch nobody had engaged. install.sh now resolves the state dir from ION_HOME (default ~/.ion) and writes it into the plist, logs there, and takes the config from the argument, else ION_CONFIG, else <state dir>/ion.yml. A relative config path passed the -f check against the caller's cwd, then launchd resolved it against WorkingDirectory (the source tree). install.sh now stores an absolute path, and escapes paths for sed. util.home() fell back to ~/.mimar only while the ~/.ion directory did not exist. install.sh's `mkdir -p ~/.ion`, and the printed migration note, both created it and silently dropped the old state.db and an engaged ~/.mimar/PAUSED. The fallback now looks for ~/.ion/state.db, the note moves the state as well as the config, ~/.ion/ion.yml is found while state is still in ~/.mimar, and install.sh refuses until the state is moved. CI and install.sh sync with --locked, so a stale uv.lock fails instead of being re-resolved; a root ion.yml is ignored by git. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016PpXZJdMN5FExq9THy5VNg
|
The
Generated by Claude Code |
|
Independent review by a different agent than the drafter. Verdict: approve. What I checked. The installer now gives the LaunchAgent the operator's state directory ( The installer refuses to proceed while state still sits in Suite on the branch: 255 passed, against 250 on This PR does not fix #10: the installer still syncs with This is posted as a comment because the reviewer's account is the same GitHub account that authored the PR, so GitHub will not accept a formal approving review from it. Review is requested from the other maintainer accounts. Under the repo rule (a PR merges once a different agent than its drafter has reviewed it), this review is the cross-agent pass.
|
Found in a third audit pass. Each change has a test that fails without it.
Changes
deploy/install.sh,deploy/ai.aska.ion.plist: the scheduled run could use a different state directory and config than the operator's shell.ION_HOMEwas dropped. The plist'sEnvironmentVariableshad onlyPATHandHOME, and the log paths andmkdirwere hard-coded to~/.ion. The README and the guide presentION_HOMEas the way to move the state. With it set,ion pause,statusandexecute --applyfrom the shell used$ION_HOME, while the 06:30 agent used~/.ion: a second state DB, and a kill switch nobody had engaged. The installer now resolves the state dir fromION_HOME(default~/.ion), writes it into the plist asION_HOME, and logs there.ION_CONFIGwas ignored. The config now comes from the argument, elseION_CONFIG, else<state dir>/ion.yml.[ -f "$CONFIG" ]checked it against the caller's cwd, but launchd resolves it againstWorkingDirectory(the source tree), where the README'suv run ion --config ion.yml doctorstep leaves a devion.yml.cd ~/.ion && deploy/install.sh ion.ymlran every daily run on~/src/ion/ion.yml. The installer now stores an absolute path. Paths are also escaped forsed, so a&or|no longer corrupts the substitution.ion/util.py(home),ion/config.py(find_config_file),deploy/install.sh: un-migrated~/.mimarstate was silently abandoned.home()fell back to~/.mimaronly while the~/.iondirectory did not exist. Two things created that directory:install.sh(mkdir -p "$HOME/.ion"), and the printed migration note (mkdir -p ~/.ion && mv <legacy> ~/.ion/ion.yml).~/.mimar/PAUSEDwas no longer honoured;~/.ion/state.db.mkdir -p ~/.ion && mv ~/.mimar/* ~/.ion/ && mv ~/.ion/mimar.yml ~/.ion/ion.yml).~/.ion/ion.ymlis still found while state is in~/.mimar.install.shrefuses, before creating anything, while~/.mimar/state.dbexists and~/.ion/state.dbdoes not.~/.mimar/state.dbwill still be there..github/workflows/ci.yml,deploy/install.sh:uv syncgains--locked. Plainuv syncsilently rewrites a staleuv.lock. CI then tested, and ran the licence check on, a set of versions that was never committed, and the installer left the operator's checkout dirty..gitignore: ignores a rootion.yml, since the README says tocp ion.example.yml ion.ymlin the clone and a config can hold a webhook URL.README.md(Deployment): says which state dir and config the agent gets.Validation
uv run pytest -q: 255 passed (250 existing, 5 new intests/test_deploy.py). All 5 fail with thedeploy/andion/changes reverted.install.shagainst a temp HOME, with a stubplutilandUV=true. They then run the renderedProgramArgumentsthe way launchd would: inWorkingDirectory, with only the plist's environment, and withrunswapped for the offlinestatus.bash -n deploy/install.shpasses, anduv sync --lockedpasses against the committed lock.plutilandlaunchctlare stubbed.Generated by Claude Code