feat: close the three publish-surface gaps between Pi and MCP (#162, #146, #147) - #179
Merged
Conversation
human, so when the key is set in config and the call lacks confirm: true it refuses with an InvalidRequest whose text previews the publish (library, entry, new version vs metadata-only update via the new read-only previewPublishVersion that publishEntry now also uses, source_repo, headline, confidentiality) and says to re-invoke with confirm: true. Nothing is written. The gate applies only when a config layer actually set the key (library.publish_confirm_configured), since the loader's default of true exists for Pi's dialog; hosts that never configured it see no change. carrying recorded and incoming (message unchanged), mirroring ConfidentialityMismatchError, and /codecarto-publish catches it to ask whether the repository moved — yes retries with allowSourceRepoChange, no writes nothing. Overrides accumulate so a publish tripping both guards is asked both questions. the new resolvePublishSourceRepo (origin's fetch URL, else the remote the current branch tracks, else the directory; only at the work tree root so monorepo subdirectories keep distinct slugs). Stored verbatim, slug derived from the same value, and deriveSlug handles the slash-less git@host:name form. Entries an earlier Pi published hold a path, so the first publish after upgrading trips the guard — #146's question is the remedy, and the docs say so. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
TheAmericanMaker
force-pushed
the
feat/publish-parity
branch
from
September 7, 2026 15:02
84561ca to
457d4a6
Compare
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three publish-surface gaps between Pi and MCP, closed together because #147's upgrade path is exactly the case #146's confirm exists for.
#162 — MCP honors
library.publish_confirmhandlePublishnever read the key; onlycodecarto_configdisplayed it. MCP cannot ask a human, so it now does whatcodecarto_broadsidedoes for its spend limit: when the key is set and the call lacksconfirm: true, it throwsMcpError(InvalidRequest)whose text is the preview Pi would have shown (library, entry, new version vs metadata-only update,source_repo, headline, confidentiality, spec source) and says to re-invoke withconfirm: true; the same fields ride along aserror.data. Nothing is written by the refusal.previewPublishVersion, whichpublishEntryitself now calls — so the preview and the real publish cannot drift.library.publish_confirm_configuredon the loaded config). The loader defaultspublish_confirmtotrue; honoring that default would have gated every MCP host that never touched the key.codecarto_library_initwrites the key explicitly, so libraries initialized through the tooling get the gate. Hosts that never configured it see no change.codecarto_configreports for the samecwd.confirm(boolean) added to thecodecarto_publishinputSchema.#146 — Pi: the source-repo collision guard gets an escape hatch
The guard now throws a typed
SourceRepoMismatchError { recorded, incoming }(message unchanged), mirroringConfidentialityMismatchError./codecarto-publishcatches it and asks a second confirm showing both values — "did the repository move?" Yes retries withallowSourceRepoChange: true; no notifies "Publish cancelled. Nothing was written." The publish loop accumulates overrides, so a publish that trips both guards is asked both questions in turn.#147 — Pi records the git remote as
source_repoNew
resolvePublishSourceRepo(cwd)in core (next tocommitPublish, reusingrunGit):origin's fetch URL, else the fetch URL of the remote the current branch tracks, elsecwd. Stored verbatim; normalization stays at comparison time (#127). Slug derives from the same value;deriveSlugnow also handles the slash-lessgit@host:nameform so every spelling of a remote lands on the slug the directory did. The preview printsSource: <value> (git remote origin).cwdis the root of its work tree (realpath-compared). A monorepo subdirectory keeps recording its path — otherwise every subdirectory would resolve to one URL and one slug and the second published would silently land as v2 of the first, with no guard able to tell.docs/library-format.md(source_reporow and "Source repo conflicts").Tests
535 passing (516 before; 19 added):
previewPublishVersion,SourceRepoMismatchErrorfields,deriveSlugremote/directory agreement, the resolver against real temporary git repos (origin, upstream-only, no remote,.remote, non-git, subdirectory, symlinked root), the MCP gate (refusal + preview + nothing written,confirm: true, unset/false unchanged, workspace-over-user layering,=== trueonly, gate runs after validation), and a newtests/pi-publish.test.mjsharness (records the remote and derives the slug from it, non-git path fallback, the upgrade collision answered yes/no, preview decline).tests/mcp-library.test.mjsandtests/publish-path-containment.test.mjsnow pinCODECARTO_USER_CONFIG_PATHto a nonexistent file: with the gate live, a developer's real~/.codecarto/config.yaml(publish_confirm: true, as library-init writes) would otherwise refuse every existinghandlePublishtest locally while CI stayed green.Closes #162
Closes #146
Closes #147
🤖 Generated with Claude Code