Skip to content

Record the sync point a publish creates - #63

Merged
rhiever merged 5 commits into
mainfrom
fix/publish-records-sync-point
Jul 28, 2026
Merged

Record the sync point a publish creates#63
rhiever merged 5 commits into
mainfrom
fix/publish-records-sync-point

Conversation

@rhiever

@rhiever rhiever commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

goodeye skills publish moved the registry without ever touching the local sync index. A directory publish set both drift signals at once: the uploaded tree left the recorded hashes on superseded content while the version advanced, which classifies as a conflict. Nothing could clear it, because a pull refuses a dirty tree and a push sends a token the registry has already replaced, so the mirror stayed stuck until a forced pull discarded the local edits it was protecting.

What changes

A directory publish records the whole sync point, found by the published directory's own path. The tree was uploaded, so the registry holds what the directory holds whatever version the index was sitting at, which also recovers a mirror already stranded.

A body-only publish reads no directory, so it records only what it knows, only on mirrors sitting at the version it replaced, and writes the new body to disk only when nothing unsaved is there to lose. A mirror holding unsaved edits keeps them and reads as ordinary drift a push resolves.

Publishing a directory also cleared every sibling-file label and execute bit. Both live only in the registry, and a snapshot that omits one clears the stored value, so a tracked mirror's recorded labels and execute bits now ride along with the upload the way a push already sends them. For an unchanged file the recorded execute bit wins, which is the rule build_files_payload already applies on a push, so publish and push cannot disagree about the same directory. build_files_payload itself is untouched.

Verification

  • Full suite: 1125 passed. ruff, ruff format and pyright all clean.
  • The new tests were run against the unfixed source: 7 of 13 fail. The 6 that pass unfixed are the "leaves the index alone" guards, which hold trivially when nothing writes the index, so they guard against over-reach rather than reproduce the bug.
  • The best-effort contract is covered in both directions: an unreadable index or an unwritable mirror warns without failing a publish that already landed on the registry.

Not in scope

  • A publish of an untracked directory still clears labels. The server's save path snapshots while its patch path carries labels forward; making the two consistent is a server-side change.
  • Prompt packs that pipe a body-only rewrite through publish - would be better served by put-file.
  • The public docs do not yet describe the new local side effects of a publish. Tracked as a docs follow-up.

Release

Version bumped to 0.25.3. This release carries only the bug fix: the single-path file commands shipped in 0.25.2. Not tagged yet. The changelog entry lives in the server repo and ships as a separate PR.

🤖 Generated with Claude Code

rhiever and others added 5 commits July 28, 2026 15:16
`goodeye skills publish` moved the registry without ever touching the
local sync index. A directory publish set both drift signals at once: the
uploaded tree left the recorded hashes on superseded content while the
version advanced, which classifies as a conflict. Nothing could clear it,
because a pull refuses a dirty tree and a push sends a token the registry
has already replaced, so the mirror stayed stuck until a forced pull
discarded the local edits it was protecting.

A directory publish now records the whole sync point, found by the
published directory's own path. The tree was uploaded, so the registry
holds what the directory holds whatever version the index was sitting at,
which also recovers a mirror already stranded. A body-only publish reads
no directory, so it records only what it knows, only on mirrors sitting at
the version it replaced, and writes the new body to disk only when nothing
unsaved is there to lose.

Publishing a directory also cleared every sibling-file label. A label
lives only in the registry, and a snapshot that omits one clears the
stored value, so a tracked mirror's recorded labels now ride along with
the upload the way a push already sends them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A directory publish builds its snapshot from the walk alone, so the
recorded manifest is the only source for anything the walk cannot recover.
The role label was already carried back; the execute bit was not.

A filesystem that does not preserve the bit reports every file as
non-executable, so publishing from a Windows checkout or a FAT/exFAT mount
cleared a flag the registry rightly held, and now recorded that loss in the
manifest as well. For a file whose content is unchanged the recorded bit is
authoritative, the same rule a push already applies; a changed file still
carries what disk reports, since its content and any permission meant to go
with it are what is being uploaded.

Also wrap a test line the formatter rejected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A publish reaches the local index only after its write has landed on the
registry, so an unreadable index or an unwritable mirror warns and moves on
rather than reporting a completed publish as a failure. Nothing tested that,
so a change letting the exception escape would have turned a successful
publish into an error. Two tests pin it, one per input mode.

A push records the verifier refs a save left behind, which is what
`_bindings_from_save` was extracted for, so it goes through the helper
instead of repeating the comprehension.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This branch carries only a bug fix (the publish sync-point record and
best-effort index reuse), not a feature. The single-path file commands
that originally justified a minor bump already shipped in 0.25.2
(tag v0.25.2). No v0.26.0 tag exists yet, so nothing is pinned to it.
@rhiever
rhiever merged commit 74c7b4d into main Jul 28, 2026
1 check passed
@rhiever
rhiever deleted the fix/publish-records-sync-point branch July 28, 2026 23:54
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