Skip to content

codex: sync Jesssullivan/main -> tinyland/main (#534 keep-both + truth docs, 2026-07-06)#71

Merged
Jess Sullivan (Jesssullivan) merged 21 commits into
mainfrom
codex/sync-origin-main-20260706-pr534-pr535
Jul 6, 2026
Merged

codex: sync Jesssullivan/main -> tinyland/main (#534 keep-both + truth docs, 2026-07-06)#71
Jess Sullivan (Jesssullivan) merged 21 commits into
mainfrom
codex/sync-origin-main-20260706-pr534-pr535

Conversation

@Jesssullivan

@Jesssullivan Jess Sullivan (Jesssullivan) commented Jul 6, 2026

Copy link
Copy Markdown

Summary

Linear: TIN-2552, TIN-1620

Validation

  • git merge completed cleanly
  • git diff --check

No local cargo/nix builds were run on neo; this sync relies on GitHub CI.

…(ledger item 9, TIN-1417)

Verified-in-source semantics of tcfs device revoke (local signed mark,
no auto remote sync, revocation-sticky merge), the wrap-mode effect
matrix, the roll-call coupling that puts the 3 local-fileprovider-*
ghosts on the PerDevice critical path, residual risks (FP identity
liveness pre-check), and the exact parked operator packet. Doc-only:
no devices revoked.
…genuinely diverged repos

Design-first doc for the non-fast-forward half of G5-git-5, grounded in the
merged Jesssullivan#513 semantics. Core insight: the loser's objects already roam while
refs conflict, so keep-both = parking losing heads as refs/tcfs/theirs/<device>/**
via git update-ref — no data movement, both histories fsck-clean, human merges
with ordinary git. Flags two LIVE corruption vectors to fence first (per-file
ResolveConflict RPC + NATS auto-resolve splice). Increments PR-1..PR-4 with
per-PR evidence bars; new harness rows G5-git-6..14; G5-git-13 flips
G5-git-5/T10/T11 green. Six open operator questions gate PR-3.
… `tcfs conflicts` read verb

Rung 1 of the divergent-.git keep-both design (docs/design/
git-divergent-keep-both-2026-07-02.md §5 PR-1, Jesssullivan#523). Pure safety +
visibility: zero new write capability, no operator decision, no deploy
dependency. Closes two .git-corruption vectors reachable on the fleet today.

Live vectors fenced:
- grpc.rs resolve_conflict had no .git guard, reachable via CLI `tcfs
  resolve` and the MCP resolve_conflict tool (passthrough to the same RPC):
  keep_remote/keep_both on a .git ref splice one device's ref/index over the
  other's object store (G5-git-5 fsck corruption; no lock, no fsck, no
  objects-before-refs order).
- daemon.rs NATS auto-resolve applied AutoResolver per file with zero .git
  awareness, auto-downloading a remote ref over the local object store.

Pieces:
1. grpc.rs: refuse keep_local/keep_remote/keep_both on any .git-internal
   path with repo-group guidance; defer stays a no-op (allowed). Non-.git
   files resolve exactly as before. Auto-covers the MCP tool.
2. daemon.rs: NATS conflict_mode=auto defers .git-internal conflicts
   (record + skip); non-.git conflicts keep today's auto behavior.
3. tcfs-cli: new read-only `tcfs conflicts` verb — reads the state cache
   (no daemon RPC), groups .git conflicts by repo root, shows local HEAD
   (git log --oneline -1), age, times_recorded, honest remote-HEAD
   degradation; --json. No writes.
4. ConflictInfo.times_recorded: u64 (serde(default)), bumped at the reconcile
   record site on re-record (detected_at preserved) so a forever-Conflict
   repo is visible; old state caches deserialize to 0.
5. cmd_resolve interactive prompt now loads the real ConflictInfo from the
   state cache instead of a dummy placeholder.

Tests: .git fence refuses keep_* / allows defer / ignores normal files;
NATS-auto defers .git; ConflictInfo round-trips without times_recorded -> 0;
`tcfs conflicts` groups by repo and classifies head-ref vs other .git paths.

Later rungs: PR-2 hard lock respect (+ remote_manifest_key), PR-3 the
resolve_git_keep_both verb (gated on §6 Q1-Q6), PR-4 loser-side no-loss guard.
…pr1-fence

feat(keep-both PR-1): fence .git conflicts from per-file resolution + `tcfs conflicts` read verb
…host-device-revocation-safety

docs(ops): ghost-device revocation safety analysis + parked packet (ledger item 9, TIN-1417)
…ecord-2026-07

docs: dated decision record for the 2026-07-01 operator session
Close alias bypasses by checking resolved paths and stored conflict rel_path, persist deferred git auto-conflicts before acking NATS events, and normalize conflict grouping paths.
…ix (Jesssullivan#529)

Adversarial-review fixes for the live .git keep-both write path.

BLOCKING 1 — operator-deliberate (CLI-only) execute path:
- MCP resolve_conflict now rejects any resolution starting with
  "git_keep_both" before it can reach the daemon RPC, pointing at the CLI
  (tcfs-mcp/src/server.rs).
- Add proto field ResolveConflictRequest.operator_cli (field 3), set only by
  the `tcfs resolve` CLI. The daemon gates git_keep_both_* dispatch on it and
  fails closed when absent; MCP's ResolveConflictInput cannot set it, and no
  auto/NATS path does (tcfsd/src/grpc.rs, tcfs-cli/src/main.rs, proto).

BLOCKING 2 — undo bundle out of the repo .git:
- write_undo_bundle now writes to <state_dir>/keep-both-undo/<repo-hash>/ under
  the machine-local state dir (never a sync root), only when refs actually
  change (conflict_git.rs, grpc.rs undo_bundle_state_dir).
- blacklist fail-closed denies any .git/tcfs-undo/** path so a pre-existing
  in-tree bundle can never roam (tcfs-sync/src/blacklist.rs).

CHANGES-NEEDED 3 — real end-to-end Execute test:
- Two genuinely divergent repos: asserts theirs parked at the correct SHA,
  winner head/HEAD/objects untouched, `git fsck --full` clean, both heads
  reachable, and a second Execute is idempotent (conflict_git.rs tests).

CHANGES-NEEDED 4 — veto over-breadth reconciled:
- collect_repo_conflicts only vetoes genuinely unparkable ref-class paths
  (packed-refs, refs/ outside refs/heads/, detached HEAD, submodule refs);
  index/logs/COMMIT_EDITMSG ride kept-local so the verb works on real divergent
  repos. Reuses reconcile::is_git_ref_class_path (now pub(crate)).
…pr3-repo-resolve

feat(sync): add repo git keep-both resolver
…oy-gated

Adds an implementation-status table + the ratified operator §6 answers + the
PR-3 adversarial security note (operator-CLI-only execute; state-dir undo
bundle). PR-1 (Jesssullivan#526/afd84b2), Jesssullivan#527 hardening, PR-2 (Jesssullivan#528/1e41a23), PR-3
(Jesssullivan#529/831d363b) all merged; PR-4 (loser-side no-loss guard) is the only
remaining rung and is gated on the fleet reaching a common tcfs version
end-to-end (neo v0.12.16 deploy, itself blocked on the PZM builder hardware).
…rgent-keep-both

design: divergent .git keep-both (T10/T11 — the non-FF half of G5-git-5)
…alf (TIN-1620) (Jesssullivan#532)

honey<->neo bidirectional .git roam converges via Jesssullivan#513 FF resolution on the
deployed v0.12.16 fleet, both directions, 0 conflicts, fsck clean — where the
2026-06-09 canary stalled at 5 conflicts. The R3 handoff works: work on either
host, resume on the other.
…oupled from Jesssullivan#517 crypto) (Jesssullivan#531)

Delivers the stated purpose of Jesssullivan#517 (evidence rescue) WITHOUT the bundled WIP
key-rotate crypto, which is BLOCKED (revocation-defeating defects, 65 commits
stale — see Jesssullivan#517 review). 36 evidence files missing from main: the
large-workdir-20260526 parity packet, shadow-inventory, and related roam-canary
artifacts. Docs-only; no code.
…ivan#534)

* git keep-both: park loser heads before ref pulls

* docs: mark keep-both PR-4 in remote validation

* git keep-both: defer non-head ref overwrites

* harness(G5-git-13): loser-side no-loss guard two-machine convergence

Add the G5-git-13 stage to the .git-as-files fsck/conflict harness — the
PASS counterpart to Stage 4's corruption-risk evidence. It reproduces the
keep-both PR-4 loser-side no-loss guard (design S10) at the ref level with
pure git on BOTH machines and asserts the no-loss invariant: after a
divergent .git pull overwrites refs/heads/main with the winner head, the
loser's committed head is parked at refs/tcfs/theirs/<self_device>/heads/*
first, so both sides' committed heads stay reachable (rev-list --all) and
each .git is fsck-clean. This is the two-machine convergence row that
flips G5-git-5 green (closes the converges-never gap).

Fail-before/pass-after verified: with the park the stage exits 0 (PASS);
neutralizing the park orphans the loser tip and the stage exits 1
("loser tip unreachable (ORPHANED)").

* git keep-both: harden loser guard edge cases

* fix(keep-both PR-4): test helper reads manifest key from remote index

The loser_guard tests' upload_ref_blob helper returned UploadResult.hash
(the file-CONTENT hash) as the pull manifest_hash, but the ref blob is
retrievable only at its remote-index manifest key (manifest_object_id).
download_ref_sha_from_manifest therefore always returned None, so every
guard path fell through to the "incoming SHA unreadable" DEFER — which the
three defer-expecting tests passed on coincidentally while
loser_guard_parks_divergent_local_head_before_ref_pull (which needs the
incoming SHA to prove the non-ancestor overwrite and park) failed on CI.

Read the manifest key from list_remote_index(...).manifest_hash, matching
the working git_ff_resolution seeding pattern. All four loser_guard tests
now exercise a real incoming-SHA download: the parks test parks + applies,
the defer tests defer via their intended non-parkable/module paths.

* git keep-both: guard ref deletes and suffix collisions

* docs: correct PR-4 builder blocker framing

* git keep-both: CAS-protect loser ref mutations

* git keep-both: close ref-class raw fallthroughs

* git keep-both: guard symbolic submodule HEAD

* git keep-both: validate new packed-refs syntax
@Jesssullivan Jess Sullivan (Jesssullivan) merged commit 88a4ee6 into main Jul 6, 2026
13 checks passed
@Jesssullivan Jess Sullivan (Jesssullivan) deleted the codex/sync-origin-main-20260706-pr534-pr535 branch July 6, 2026 04:07
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