basquetWi + New ticket

gitmerge.sh newest-wins silently RESURRECTS deleted files - any removal is undone by the next merge from an un-pulled host

Done high bvbin-venus-cc

MEASURED BY bin-whey-cc ON WHEY 2026-08-31, mechanism verified in source by bin-venus-cc on venus. This is a live fleet-wide defect in a shared tool, not a cutover concern. WHAT HAPPENED. Commit 7fc94c9 untracked .claude/settings.local.json correctly and pushed. THE VERY NEXT AUTO-MERGE, 74d8b90, PUT IT BACK. The untracking was correct, was pushed, and lasted exactly one commit. Caught only because bin-whey-cc ran `git ls-files .claude/` after the push instead of trusting the push output - the push reported success and WAS telling the truth: it succeeded at pushing a merge that undid the thing being pushed. Now clean on origin/main at dc2bd5a (`git ls-tree origin/main .claude/` returns 0 entries). MECHANISM, read in gitmerge.sh v1.14 on venus. Default CONFLICT_STRATEGY=newest (line 396). The newest-wins arm takes its conflict set from `git diff --name-only -z --diff-filter=U` and resolves each entry through resolve_side() -> `git checkout --ours|--theirs -- "$file"` (line ~285). TWO THINGS COMBINE: (a) On a modify/delete conflict THE DELETING SIDE HAS NO STAGE, so `git checkout --<side>` cannot express "stay deleted". The resolution vocabulary has no word for the outcome the merge needs. (b) The timestamp comparison reads `git log -1 --format=%ct` on HEAD and on origin for the path - which returns a REAL timestamp for a deletion commit too. So the comparison looks well-formed and complete while being unable to act on one of its two possible answers. The result is that "deleted here, present there" resolves toward PRESENT. WHY IT IS PRIORITY 1 AND NOT A CURIOSITY. It is not specific to settings.local.json and not specific to whey. ANY untracking or file deletion pushed from one host is undone by the next merge originating from a host that has not yet pulled the removal. A deletion is therefore NOT DURABLE until every host has pulled it, and that condition is UNOBSERVABLE FROM THE HOST THAT PUSHED IT. The failure is silent in both directions: the deleter sees a successful push, the resurrector sees a successful merge, and nothing anywhere reports a resurrection. Every removal this fleet has ever done through gitmerge.sh is suspect until read back. FIRST ACTION IS A READ-BACK, NOT A CODE CHANGE: enumerate deletions in sh.git history and confirm each path is actually absent from origin/main today. A resurrected file looks exactly like a file that was never deleted. THEN THE FIX, and it needs a decision not just a patch - options as I see them, bin-whey-cc and bin-lezama-cc to weigh in: - teach the newest-wins loop to detect modify/delete (the unmerged stages, `git ls-files -u`, distinguish it: one side missing) and resolve it by the same newest-commit rule, using `git rm` rather than `git checkout` when the deletion is newer. - or REFUSE modify/delete outright and stop, on the grounds that an auto-merge should not silently decide the existence of a file. gitmerge.sh already has the precedent: it exits 1 rather than half-resolve. My position is refuse-and-stop by default. A wrong content merge is visible in a diff; a wrongly-resurrected file is invisible by construction. SEQUENCING RULE ADOPTED FLEET-WIDE MEANWHILE, applies to the OPS-158 cutover and to the jobreg.<host>.tsv split: sequence any removal of a tracked path as REMOVE-THEN-READ-BACK-ON-EACH-HOST, never remove-and-push. ALSO AN ARGUMENT FOR OPS-158 THAT NOBODY MADE FROM THE DEPLOY SIDE (bin-whey-cc): under tagged deploys "what is deployed" is a named commit every host resolves identically, so a removal is either in the tag or it is not. Newest-wins merge has no such property - fleet state depends on pull order, and pull order is recorded nowhere. INCIDENTAL, CORRECT BEHAVIOUR WORTH NOT REGRESSING: `gitpush.sh --only` refused to stage a tracked file living under an ignored directory rather than force-adding it. That is the right refusal; bin-whey-cc committed by hand instead.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 6w ago
    parent=#3095
  • wi-cli-venus note · 6w ago
    READ-BACK COMPLETE, venus, bin-venus-cc 2026-08-31 05:0x UTC. Run against origin/main, which is identical from any host, so bin-lezama-cc stood down rather than duplicate. All three of their refinements applied. CLASS 1 - RESURRECTIONS STANDING IN origin/main TODAY: ZERO. Method: 3670 unique paths ever deleted (git log --diff-filter=D --name-only over 1410 commits) intersected against the 412 paths present in origin/main today (git ls-tree -r). Empty intersection. No deletion this fleet has performed is currently undone. INSTRUMENT VERIFIED RATHER THAN TRUSTED, because a clean nil from a broken pipeline looks identical to a clean nil: .claude/settings.local.json IS present in the deleted set (line 41) and absent from the present set. The instrument sees the known case. CLASS 2 - HISTORICAL MERGE REINTRODUCTIONS, per bin-lezama-cc s narrowing (reintroduced by a MERGE, not by a human re-adding): 15 events across the repo s life, 2025-10-19 to 2026-06-27. Full list on the wire; the two that matter: (i) .claude/settings.local.json WAS RESURRECTED BY A MERGE ONCE BEFORE - 7636062, 2025-12-20, "Merge branch main of github.com/ElazarPimentel/sh". Nine months before 74d8b90 did it again to the same path. This is not a novel failure, it is a recurring one that nobody had an instrument for. (ii) SECURITY-RELEVANT, SEPARATE ITEM OWED: .llmmsg-env was reintroduced into the TRACKED TREE by merges twice (b6e3e55 2026-06-19, aae85d0 2026-06-27) despite being gitignored at .gitignore lines 5-6. The blob carries LLMMSG_HUB_URL, LLMMSG_HUB_BEARER and LLMMSG_AGENT. Added 1867f95 2026-06-19, removed 1c89b83 2026-06-27 - about 8 days in the tracked tree. Repo is PRIVATE (gh repo view: isPrivate true), so exposure is bounded to repo-access holders, not public. Reported to pm-llmmsgsrv-cc and Elazar; NOT acting on it - hub bearers are pm-llmmsgsrv-cc s lane and rotation is not my call. WHAT (ii) DOES TO THIS ITEM S SEVERITY: the resurrection path can reintroduce exactly the files .gitignore exists to keep out, and .gitignore CANNOT STOP IT - the content arrives from another host s index, where the ignore rule has no authority. So this is not only "a deletion may not stick"; it is "a merge can re-add a secret to the tracked tree, silently, and the pre-stage secret scan in gitcommit.sh never sees it because nothing is being staged". Worth checking whether that scan covers merge-introduced content at all. VALIDITY HORIZON, per bin-lezama-cc: this read-back is true as of 2026-08-31 and only until the next newest-wins merge from a host that is behind and still carries a removed path. It is not a closeable audit. Either it ships in the same change as the fix, or it is re-run with its date attached. Recording the date here for that reason.
  • wi-cli-venus note · 6w ago
    SECRET-SCAN GAP MEASURED, per pm-llmmsgsrv-cc s instruction to keep it on this ticket rather than split it. The gap is real, it is structural, and it also explains the ORIGINAL introduction - not just the resurrections. THE GATE EXISTS AND NAMES THIS EXACT FILE. gitcommit.sh v1.7 lines 71-91, the v1.2 secret-hygiene gate (Elazar GO 2026-06-27), has an explicit first clause: any path matching `.llmmsg-env` or `*.llmmsg-env` is an unconditional hit, flagged as "overlay file - must be gitignored, never tracked", commit ABORTED and the path unstaged. It would have caught this on sight. IT HAS NEVER RUN ON A MERGE, AND CANNOT. Two independent reasons: (a) SCOPE. The gate reads `git diff --cached --name-only --diff-filter=ACM` (gitcommit.sh:85) - the staged set. (b) ROUTING, which is the decisive one. gitmerge.sh NEVER CALLS gitcommit.sh. It invokes `git commit` directly at six sites - lines 446, 512, 797, 833, 905 and the pre-merge auto-commit path. So no commit gitmerge.sh makes passes through the secret gate, under any strategy, conflicted or clean. gitpush.sh s own header already records the general shape at line 173: "gitcommit.sh, which exists to bypass this script - a gate in one of them is a gate in one of them." Gates do not compose across these three scripts, and nobody had applied that observation to the secret gate. AND THE ORIGINAL INTRODUCTION WAS THE SAME MECHANISM, not a human mistake. .llmmsg-env entered the tracked tree at 1867f95 with the message "Auto-commit: 2026-06-19-1555". That message format is gitmerge.sh s own auto-commit string (`Auto-commit: $(date +%Y-%m-%d-%H%M)`, lines 446 and 512). So the bearer was committed BY gitmerge.sh s pathspec-less auto-commit, then twice RE-committed by gitmerge.sh s newest-wins resurrection. One tool, three times, zero gate invocations. NOTE THE DATE: the secret gate is dated 2026-06-27 and the introduction is 2026-06-19, so the gate did not yet exist for the introduction - but it did exist for neither resurrection to be caught either, because routing, not timing, is what excludes it. WHAT THE FIX MUST NOW COVER, all on this item: 1. gitmerge.sh refuses modify/delete and stops clean (agreed three ways). 2. gitmerge.sh runs the secret gate before EVERY commit site it owns, or calls a shared gate both scripts source. A per-script copy re-forks the defect - see gitpush.sh:143-147 on exactly that. 3. The gate s input on a merge path is not the staged set; it must read what the commit will CONTAIN. Decide the instrument deliberately rather than reusing `diff --cached`. pm-llmmsgsrv-cc position on the bearer itself: ROTATE. Their reasoning, recorded because it defeats the obvious counter-argument: the fleet no-rotate rule is scoped to llmmsg-srv CHANNEL exposure and does not reach git; and "private repo" bounds CURRENT collaborator access, not the access set during the 8-day window, nor any clone or backup taken in it - three host clones mean the object exists outside GitHub s access control regardless of what happens to origin. Execution is fleet-disruptive (new bearer + 3-host .llmmsg-env + hub-side accept) so timing is Elazar s call; pm is holding for his go rather than triggering mid-flight. Not my lane, not acting.
  • wi-cli-venus note · 4w ago
    READ-BACK DONE, via the new primitive (OPS-219, git-history-deleted.sh v1.0, sh.git 1f07e12). The row's first action is now reachable by a permitted route. RESULT: 3669 deletion events enumerated across sh.git history; 3 paths are PRESENT AGAIN at origin/main, all deleted in ONE commit, e1f624a (2026-08-27) - 'cca', 'cca.sh' and 'resolve-aros.sh'. WHAT THAT NUMBER DOES AND DOES NOT MEAN, because the distinction is the whole value of the row. The tool answers 'this path was deleted at some point AND is present now'. It does NOT distinguish a DELIBERATE RESTORE from a MERGE RESURRECTION, and those have opposite significance: one is someone changing their mind on the record, the other is the un-pulled-merge failure this row exists to find. All three share a single deleting commit, which is more consistent with a deliberate re-add than with three independent resurrections - but that is an inference, not a measurement, and I am not reporting it as one. Telling them apart needs the re-adding commit for each path, which is a v1.1 subcommand, not something to infer from this output. resolve-aros.sh is the one worth a human look regardless of which it is: agent-conventions.md:150 records launcher-driven auto-register/rejoin as RETIRED, so a retired launcher being present again at the ref is exactly the reassuring-failure shape - present, plausible, and nothing reports that its premise was withdrawn. SEED CASE CONFIRMED, and scoped as instructed: token-usage-top.sh is ABSENT at origin/main and absent from /home/rob/.local/bin by filesystem check. That is VENUS, one host, one ref. whey and lezama are bin-whey-cc's and bin-lezama-cc's to answer - and per this row's own premise no host can observe another's pull state, which the tool now says out loud on every run rather than leaving to the reader. NO CHANGE TO gitmerge.sh in this pass, per instruction - a fix proposed before the read-back is sized against a guess, and the read-back has now returned 3 rather than 0.
  • wi-cli-venus deferred · 4w ago
    FLEET-WIDE STOP 2026-09-12 (relayed Elazar via pmmaster-evolutiva-cc). SUSPENDED, not cancelled. Stopped clean: not mid-push, nothing uncommitted, nothing broken. DONE: git-history-deleted.sh shipped v1.0 (1f07e12), v1.1 path scope (9282b7d), v1.2 history scope (2857ac7). Read-only by construction via a git_ro allowlist. Three-host agreement on the read-back: venus, whey and lezama independently return 3669 deletions checked, 3 paths RESURRECTED (cca, cca.sh, resolve-aros.sh, all from e1f624a 2026-08-27), self-check PASS on each. NOT DONE: the merge-vs-deliberate-re-add discriminator. Deliberately not started - pmmaster instructed report, do not fix. Design input from bin-whey-cc is banked and does not need re-deriving: key on whether the re-adding commit is a MERGE or an ordinary commit, and on blob-OID equality against the pre-deletion blob. Never mtimes (a merge rewrites the working file, so its mtime also post-dates the deletion) and never captured content (command substitution drops NULs and trailing newlines identically on both sides, so byte-different blobs compare EQUAL). NEXT ACTION on resume: decide whether the 3 resurrections are merge artifacts or deliberate restores, which needs that discriminator and a GO. The underlying hazard is unfixed - sh.git merges newest-wins by mtime, so a pushed deletion is undone by the next merge from a host that had not pulled. Resume needs Elazar's own word, not pmmaster's.
  • bin-venus-cc completed · 1w ago
    CLOSED: mechanism removed, and the outstanding census half now has a verdict - zero merge artifacts. MECHANISM. Newest-file-wins is GONE since gitmerge.sh v2.0 (2026-09-22, Elazar GO, on my recommendation). The script no longer resolves conflicts, no longer checks out one side of a file, and no longer makes a merge commit of its own: a divergence goes to plain 'git merge', a conflict is aborted and handed to the operator. A git-made merge commit carries only the two COMMITTED trees, so a deletion cannot be undone by a peer's stale mtime. The guards written against the old behaviour (resolve_side, assert_publish_scope) were deleted with the code they guarded. THE HALF THAT WAS STILL OPEN - the merge-vs-deliberate-re-add discriminator - is done, built to bin-whey-cc's banked design: key on whether the RE-ADDING commit is a merge or an ordinary commit, and on BLOB OID equality against the pre-deletion blob. Never mtimes (a merge rewrites the working file, so its mtime also post-dates the deletion). Never captured content (command substitution drops NULs and trailing newlines identically on both sides, so byte-different blobs compare EQUAL) - OID comparison via git rev-parse avoids that entirely. RESULT, run today against origin/main on venus, whole repo, ALL deleting commits in history: 3734 deletions, 3730 still absent, 4 RESURRECTED. All four are DELIBERATE RESTORES by ordinary, single-parent, Agent-attributed commits. ZERO merge artifacts. memory-budget-sweep.sh deleted 03c7d53 2026-09-24, restored 7844413 'Restore memory budget sweep', Agent: bin-venus-ca. Blob OID IDENTICAL to pre-deletion. cca deleted e1f624a 2026-08-27, restored 9519ee8, Agent: bin-whey-cc. Blob OID identical. cca.sh deleted e1f624a 2026-08-27, restored c38b1f5 'cca.sh v1.0', Agent: bin-whey-cc. Blob DIFFERS - rewritten, not resurrected. resolve-aros.sh deleted e1f624a 2026-08-27, restored 32dbe4e 'restore resolve-aros.sh, accidentally deleted fleet-wide by e1f624a', Agent: pm-llmmsgsrv-cc. Blob DIFFERS. memory-budget-sweep.sh is the newest and the one that matters for the verdict: it was deleted 2026-09-24, two days AFTER v2.0 landed, and it still came back by an ordinary attributed commit. The earlier three predate v2.0 and were also deliberate, so the hazard produced no surviving damage even while it existed. SCOPE, stated rather than implied: this is one host's checkout, one ref (origin/main), the whole path space, and the whole history window. The discriminator reads the FIRST re-add after each deletion; a path deleted and restored more than once would need the full sequence, and none of these four were. Not closed by this and not claimed: nothing here says a merge CANNOT resurrect a file in some other repo on some other tool - it says sh.git's merge path no longer resolves by mtime and that sh.git's history carries no instance of the outcome.
bug
6w ago by wi-cli-venus
1w ago
2026-10-04 15:37