basquetWi + New ticket

sh.git: ~/.local/bin becomes a deployed versioned artifact, not a live editable checkout

Backlog high bvbin-venus-cc

SOLUTION 2 of 2 for OPS-156. Elazar directive: bin-venus-cc, bin-whey-cc and bin-lezama-cc decide together, then implement. Couples to OPS-157 - the isolation fix is incomplete without this one, because if agents keep editing the live PATH directory the tree is shared again whatever the branching model. PROBLEM: the checkout IS the deployment. ~/.local/bin is simultaneously the git working tree, the editing surface for every agent, and the directory the whole fleet executes from. Consequences already measured in this repo: a half-saved edit is immediately live to every session on the host; an agent pulls and silently changes another agent s running tools; hosts converge FILE BY FILE (whoever pulled last, whatever was uncommitted at the time) instead of on a version, so "which sh.git is whey running" has no single answer; and there is no rollback - reverting means another edit-in-place. The three-host DM ritual after every change ("pull when convenient") is a manual replication protocol standing in for a deploy. STANDARD FIX: separate build/release from run. Tag a release on main; each host pulls that TAG to a versioned directory and flips a symlink, driven by a pull-agent (systemd timer, Ansible, or a package). ~/.local/bin becomes a deployed artifact, read-only to agents. Hosts converge on a version; rollback is a symlink flip; "what is running" is one command. DECISION NEEDED: - Release trigger: every push to main, or explicit tags. Explicit tags mean a fix is not live until someone releases it - decide if that is acceptable for hotfixes, and define the hotfix path if not. - Transport: git pull on a timer per host, Ansible push from one host, or a built tarball/package. Note lezama dials venus on 443 and the fleet has no ZT/Tailscale - whatever is chosen must work over the existing allowed directions. - Layout: versioned dirs + symlink flip vs in-place pull. Symlink flip is the one that gives rollback. - Whether the deployed tree stays writable at all (it should not) and what breaks when it is not. - Where scripts that write state next to themselves would break under a read-only deploy - audit for those BEFORE cutover, they are the failure mode that only shows up in production. CONSTRAINT: no window where a host has no ~/.local/bin. The flip must be atomic.

Activity

  • wi-cli-venus created · 6w ago
    parent=#3095
  • wi-cli-venus decision · 6w ago
    CONVERGED, bin-venus-cc + bin-whey-cc, 2026-08-31 round 1-3. Pending bin-lezama-cc ack only. RELEASE TRIGGER DECIDED: explicit tags, not release-on-merge. There is no test gate on main, so release-on-merge publishes unreviewed work to three hosts in one step. No separate hotfix path is needed - a hotfix IS a tag, cut immediately; an explicit tag costs one command, not a process. TRANSPORT DECIDED: timer-pull per host from GitHub over 443. Only option needing no new reachable direction. Ansible was rejected: it needs push-direction reach into lezama, which is banned (MSG-244). A tarball/package was rejected: no artifact store exists. LAYOUT DECIDED: versioned directories + symlink flip. Atomic via rename(2): `ln -sfn NEW .local/bin.new && mv -T .local/bin.new .local/bin`. No window; the PATH entry never changes. Rollback is a symlink flip. OPEN, and the item cannot close without it - jobreg.tsv. It is NOT runtime-written on either host (measured on venus and whey: zero redirect/sed -i/tee/mv write paths; jobreg:82 and jobreg-registry-reconcile.sh:73 are reads). So it does not break under read-only deploy. The real problem is EDITABILITY, not writability: it is a HAND-EDITED SSOT manifest, and behind a tag cut a one-row fix waits on a release. bin-whey-cc position, and mine: move it out of the tree, because the predictable outcome otherwise is someone edits the DEPLOYED copy, which is the drift this item removes. Needs bin-lezama-cc and a destination path. ALSO IN THIS CUTOVER, same commit as the flip: once ~/.local/bin is a symlink it is no longer "the sh.git checkout", and global CLAUDE.md asserts that identity as fact on all three hosts. nw-whey-cc owns that file. Raise after convergence, not before. (bin-whey-cc.) SCOPED OUT as a design item, kept as a task: .claude/settings.local.json. It is a pre-ignore index entry on whey AND lezama (.gitignore line 21 already ignores .claude/, which does not untrack what is already indexed). Untracked on venus. Fix is `git rm --cached`, not a design change - but see the sequencing note on the child/event log: a bare rm+push deletes a live Claude Code config on lezama.
  • wi-cli-venus decision · 6w ago
    FULLY CONVERGED 2026-08-31 on trigger + transport + flip mechanism (all three bin agents). THREE ADDITIONS FROM bin-lezama-cc, one of them BLOCKING. BLOCKING PRE-CUTOVER VERIFICATION - THE FLIP POINT IS NOT ~/.local/bin ITSELF. Claude Code keys each agent s memory/project directory on its cwd, encoded with / and . both mapped to "-" (this session s own key is `-home-rob--local-bin`, the double dash being the dot in `.local`). If ~/.local/bin becomes a symlink to a versioned directory AND CC resolves cwd through symlinks, every agent rooted there gets a NEW project key and its memory directory moves - silent loss of continuity for every agent on the host, not a cosmetic change. Measured on venus 2026-08-31: no existing project key corresponds to a symlinked path, so there is NO EVIDENCE EITHER WAY in the current corpus and this is genuinely unmeasured, not merely unchecked. bin-lezama-cc s mitigation is adopted because it removes the question rather than answering it: FLIP A PATH INSIDE, NOT ~/.local/bin ITSELF. If a design is proposed that does flip ~/.local/bin, the realpath-vs-literal-cwd behaviour must be measured with a real CC session FIRST. Additional exposure on lezama: 13 of its ~/.claude/*.md are symlinks INTO that tree. A CLEAN WORKING COPY IS THE DANGEROUS STATE, NOT THE SAFE ONE (bin-lezama-cc, on the .claude/settings.local.json removal). git refuses to clobber a MODIFIED file on pull; it deletes a clean one without complaint. So the host most likely to lose the file is the one that never touched it. Generalise past this item: "my copy is clean" is not a safety property when the incoming commit is a deletion. SETTINGS.LOCAL.JSON BLOCKER CLEARED. lezama index entry confirmed (blob 9eb5943, 4970 bytes, pre-ignore, .gitignore:21 present), backed up to ~/.local/state/sh-cutover-backups/settings.local.json.lezama.20260831T043829Z, md5-verified. venus backup taken 20260831T042005Z though venus is untracked. whey is clear to `git rm --cached` and push. JOBREG.TSV RESOLVED - split per host as `jobreg.<host>.tsv`, stays version-controlled, INSTALLED BY COPY NOT SYMLINK so a hot edit survives the flip, and `jobreg check` compares installed-vs-release hash and reports CONFIG on divergence. Loud divergence beats silent revert. No code change needed: JOBREG_TSV already parameterises the path (jobreg:82, jobreg-registry-reconcile.sh:73). Destination path is mine to name.
  • bin-venus-cc audit-finding · 1w ago
    PRE-CUTOVER WRITE-STATE AUDIT DONE 2026-10-06 (bin-venus-cc, venus). The row asked for an audit of scripts that write state next to themselves, calling it the failure mode that only shows up in production. The audit answers that question NO and finds a different, worse one. WRITABILITY: NOT A PROBLEM. Measured over all 427 tracked files: ZERO tracked scripts write state into their own directory. The only three hits for a write construct aimed at ~/.local/bin are setup-movilba-backup-timer.sh:8-10, and all three READ out of the tree (sudo cp FROM here TO /etc/systemd/system). Generalises the earlier jobreg.tsv finding past jobreg: a read-only deployed tree breaks no tracked script on venus. THE REAL HAZARD IS RESIDENCY, NOT WRITABILITY, AND IT IS CUTOVER-STOPPING. 11 git-ignored files live INSIDE the deployment root and are in no release, so a versioned-dir + symlink-flip loses every one of them. Ranked by what the loss costs: (1) `claude` - a symlink to ~/.local/share/claude/versions/2.1.290, and `which -a claude` returns NOTHING ELSE. It is the only claude on PATH on this host. The flip removes Claude Code from the host, which takes out every agent including whichever one would roll the symlink back. Two tracked scripts also hard-code the literal path as their default: llmmsg-wastenot.sh:70 and journal-digest.sh:12. Its mtime was 2026-10-05 23:59, so the pin moves - it is live state, not a static shim. (2) `.llmmsg-env` - mode 600, 3052 bytes, the host's SOLE credential overlay. Read by absolute in-tree path at cc.sh:141-142 ($ORIGINAL_CWD/.llmmsg-env) and defaulted to $PWD/.llmmsg-env at llmmsg-env-set.sh:81. Losing it on a flip presents as a wall of 401s across every hub-talking script and every cc session, diagnosed far from the cause. Strictly worse than jobreg.tsv, which got all the attention: jobreg's loss is visible and a one-row manifest; this one's is a credential wall. (3) `.claude/settings.local.json` - 4998 bytes of live Claude Code config. The row already knows this file is dangerous, but treated it as a TRACKED-file problem (the git rm --cached sequencing note). On venus it is UNTRACKED, so it exists ONLY in the live tree and has no copy anywhere a release could restore from. (4) `.agent-name` - 32 bytes, per-agent identity, and per OPS-271 it has two consumers with opposite subjects, so a wrong or absent value is not a cosmetic failure. (5) `wi-web` - symlink into a basquetWi project checkout. (6) `__pycache__/` x2 (7 .pyc) - MEASURED, NOT ASSUMED, and it is the one non-blocker: forced both ways in a sandbox, a writable dir creates __pycache__ while the same import under mode 555 still prints ok and exits 0 with no cache and no error. CPython skips caching silently. Cost is recompile per invocation, nothing more. THE GENERALISATION, and it is the part to carry: .gitignore IS THE INVENTORY OF WHAT THE FLIP LOSES. Every pattern in it is by construction host-local state the release cannot carry - CLAUDE.md, .agent-name*, .aro, .llmmsg-env, .vercel, .grok, *.pem, .llmmsg, claude, wi-web, .claude/, plus pipx/venv console-script shims (dnsping, dnseval, dnstraceroute, yt-dlp, f2py, numpy-config, huggingface-cli, chat-duo-cli, agent). Only 11 of those patterns have a file present on venus TODAY; the other patterns are latent, so a check that enumerates PRESENT files understates the exposure on whey and lezama, which must run this same audit rather than inherit this verdict. CONSEQUENCE FOR THE ADOPTED MITIGATION: bin-lezama-cc's 'flip a path INSIDE, not ~/.local/bin itself' is load-bearing for a SECOND, INDEPENDENT reason nobody recorded. It was adopted to dodge the unmeasured Claude-Code-project-key question; it also keeps all 11 of these files in place, because they live in ~/.local/bin and a flip of a path inside it does not move them. Any design that reverts to flipping ~/.local/bin itself must install every one of these separately, starting with claude and .llmmsg-env, and must say how. NOT COVERED: whey and lezama (this is a venus measurement only); untracked files outside the ignore patterns (there are zero today, so nothing was skipped, but that is a snapshot); and runtime writes by UNTRACKED or non-sh/py executables in the tree, which this grep over *.sh/*.py/*.mjs did not reach.
  • bin-venus-cc audit-finding · 1w ago
    TWO-HOST RESIDENCY RESULT 2026-10-06, and whey's exposure is STRICTLY LARGER than venus's - the venus verdict was not inheritable, as the child rows said. bin-whey-cc reported OPS-280 within minutes. Whey carries the SAME TWO STOPPERS: the `claude` symlink (-> /home/rob/.local/share/claude/versions/2.1.290) and `.llmmsg-env` at mode 600, read in-tree at cc.sh:141-142. So both stoppers are fleet-general, not a venus artifact, and any design that flips ~/.local/bin itself fails on both hosts for the same two reasons. WHEY ADDS A THIRD STOPPER CLASS VENUS DOES NOT HAVE: `CLAUDE.md` is git-ignored AND PRESENT IN THE TREE on whey. That is the global rule file every agent on the host reads, and a flip to a release directory loses it. Venus has the same ignore pattern with no file present, so a venus-only audit would have reported this exposure as absent. Also present on whey and not on venus: .aro, .grok/, .vercel/, monitor-context/, notifications/, codex.trace, and the pipx console-script shims (dnseval, dnsping, dnstraceroute, yt-dlp) which are regenerable. .codex/ is empty, no loss. __pycache__ x2, already settled as a non-blocker. CONSOLIDATED PRE-CUTOVER REQUIREMENT, now evidenced on two hosts: the flip must either stay BELOW ~/.local/bin (the adopted mitigation, which keeps every one of these files in place) or the design must name, per host, how each ignored in-tree file is installed into the release - starting with claude, .llmmsg-env and, on whey, CLAUDE.md. A generic 'copy the host-local files' step is not sufficient, because the sets differ per host and most patterns are latent. DIVISION OF MEASUREMENT, worth keeping: whey scoped itself to the residency inventory and deliberately did not re-measure the 427-file writability half. That is correct - the writability answer generalises (no script writes state next to itself) while the residency inventory does not. LEZAMA REMAINS UNMEASURED AND IS NOT MERELY LATE: OPS-281 is BLOCKED because no registered lezama agent seat exists on the hub at all (bin-lezama-cc and bin-lezama-ca both recipient_not_registered, forward recorded broken, and the 78-entry roster holds exactly two lezama-named registrations, both scrp senders). Lezama additionally has 13 ~/.claude/*.md symlinks INTO this tree per the 2026-08-31 note, so its exposure is plausibly the largest of the three and is the one nobody can see. THIS ITEM MUST NOT CLOSE ON A TWO-HOST RESULT.
decision
6w ago by wi-cli-venus
6w ago