Repository navigation
0.9.12: every write runs bare capy first - #396
Merged
Merged
Conversation
…es on top of the server's latest Every folder-based save (capy edit, edit NAME, add, remove, connect, rotations, push, bare capy commit-local, token revoke, the system store) used to upload the folder's whole env merged into its own keep.lock, so a folder pinned behind the server silently reverted newer values and dropped server-only variables. src/sync/commit.ts now owns every write: read the server's latest for the branch, apply only the intended set/remove on top of it (unchanged names keep the server's ciphertext verbatim), stop with SECRETS_CONFLICT when a changed name was also changed on the server since the folder's pin, upload with base_keep_hash, and re-read and re-plan once on SECRETS_STALE_BASE. capy secrets set and the deploy records send the base too. compareSecrets moves to src/sync/. The unused SyncEngine.compareEnvironments, applyDecisions, generateSyncResult, formatSyncSummary and validateDecisions are removed.
…h deploy sends only picked vars
Off a terminal a conflict stops the write, exits 3 and prints
{ok:false, code:SECRETS_CONFLICT, conflict_id, conflicts} with
fingerprints only; rerun with --resolve NAME=mine|theirs and
--conflict <id>. The id binds the decision to the state seen; a moved
state returns SECRETS_CONFLICT_STALE with a fresh id. --dry-run
previews. Shared module src/sync/conflicts.ts, used by bare capy, edit
NAME, add, remove, connect import, rotate, push, secrets set, deploy
and batch deploy.
capy deploy checks the folder against Capy's latest (a stale folder
delivers Capy's value) and, for Dokploy, the live value against what
Capy last delivered: mine delivers, theirs skips and records nothing.
Batch deploy delivers and records only the picked names, keeping the
rest of Capy's block byte-identical. capy push uploads deletions.
capy deploy's keep update goes through the commit path.
…ks before minting; deploy commits folder edits - Dokploy target resolutions carry the theirs/yours fingerprints the caller answered; a live value that moved between check and write reopens the conflict. The target comparison runs on the values actually delivered after source decisions. - capy rotate at a terminal asks about conflicts before issuing a key. - capy deploy commits a folder edit nobody else touched before delivering it, so Capy and the platform agree. - capy secrets set reuses the shared conflict printer.
…atch deploy; generated command list - capy edit compares against the server's latest (not the folder's pin), shows local / remote / conflict honestly, resolves a conflict row with m (mine) or t (theirs), and blocks commit until every conflict is decided. Decisions are bound to the values shown; a server move between showing and committing reopens the conflict. - capy secrets edit reads every location first and asks mine/theirs for a location that changed since you looked; nothing is written before. - The batch deploy screen shows Dokploy values changed outside Capy and asks before delivering. - The unknown-command list is generated from the registered commands.
capy deploy never delivers a value Capy does not hold and never saves
one unasked. A folder edit nobody else changed asks "save and deploy?"
in a terminal; off a terminal it stops with exit 3 and
{ok:false, code:DEPLOY_UNSAVED_CHANGES, names} (names only). Source
conflicts are reported first; choosing mine saves without a second
question. --dry-run reports unsaved edits and writes nothing.
…the unsaved refusal
Every command that writes from a folder (edit, edit NAME, add, remove, connect, rotate, push, deploy) runs bare capy's own sync as its first step and repeats it until the folder and Capy agree, or the person stops (nothing written). Then it applies only its own change on top of Capy's latest with base_keep_hash; a stale refusal re-runs the sync. Bare capy is restored to its documented behaviour (its tests match v0.9.11); its upload carries base_keep_hash. Off a terminal the differences are bare capy's compareSecrets rows: exit 3 with a conflict_id, answered with --resolve NAME=pinned|local|remote|delete and --conflict. Writes without a folder (capy secrets, batch deploy) compare the shown value, the new value and Capy's latest with the same choices. The Dokploy live-value check uses local/remote. Removed the conflict logic invented on this branch: findConflicts, mine/theirs and the m/t keys, DEPLOY_UNSAVED_CHANGES, the separate capy secrets check, and the narrowed commit-local.
…ehind them - capy deploy (token + docs), deploy revoke, deploy targets-remove and deploy --discover run bare capy first. - capy connect --discover gates unconditionally, and runs bare capy in each discovered folder before writing into it. - Off a terminal, an answer whose source has no value for that row is refused (SECRETS_RESOLVE_INVALID) instead of deleting the variable. - capy secrets set offers pinned / local / remote / delete; pinned writes back the shown value when it can be recovered. - No active branch off a terminal is NO_ACTIVE_BRANCH with a hint. - Bootstrap branches on the NO_SECRETS code, not the message.
…b is the one exception Switching to an existing branch and re-linking the folder to another organization both rewrite the folder's keep.lock, so they run bare capy first like every folder write. capy checkout -b does not: creating a branch carries the folder's uncommitted values onto a brand-new branch, and bare capy offers to push them there on the next sync.
… discovery failures; recovery-mode checkout - As another command's first step, bare capy compares against the branch the .env was written for when .capy/branch disagrees, so capy checkout can recover an interrupted checkout. Run directly it keeps the recovery hint. - Inside connect --discover that state is BRANCH_STATE_INCONSISTENT for the folder, and the run continues. - capy checkout in seed-phrase recovery mode switches offline. - The gate recovers a deleted keep.lock from .env metadata like bare capy does. - Real-gate tests for rotate, connect, deploy targets-remove, checkout and org.
… deploy --yes help
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.
Every command that writes from a folder now runs bare
capyas its first step and writes nothing until the folder and Capy agree. Spec: conflict resolution for every write.Gated:
capy edit(screen andNAME),add,remove,connect(and--discover, per folder),rotate,push,checkout <existing branch>,org, and everycapy deploypath.Not gated:
capy checkout -b(it carries uncommitted values to the new branch),capy decrypt, recovery-mode checkout, the system store, new project creation.pinned | local | remote | delete.base_keep_hash. If the server refuses one as stale, the command runs bare capy again and retries once.capy secretsand batch deploy compare each value they write the same way.localdelivers Capy's value;remotekeeps the platform's.SECRETS_CONFLICT, aconflict_idand the differing names (fingerprints only). Rerun with--resolve NAME=<choice>and--conflict <id>.capy agentsblock and thedeploy --yeshelp. This wording is still a draft.Draft for local testing.