- pull with .secrets.json restores exactly the declared entries (nested
paths get mkdir -p); stray store blobs are not restored
- dotenv rail re-runs at restore time: unsafe entries warn+skip (pull
never dies on one bad entry), missing blobs warn with a directed hint
- empty manifest = warn no-op instead of a confusing 'not found' death
- manifest-less projects keep the legacy glob pull verbatim
- .secrets.json external[] drives push/pull: type 'properties' (alias of
gradle-properties; blob suffix stays legacy-compatible in stage 1) and
type 'file'; same charset rails as the legacy parser
- push absorbs uncovered .secrets-files entries into the manifest
(idempotent, gradle-properties → properties) with a delete hint
- pull: manifest wins entirely; a coexisting .secrets-files warns as
superseded instead of being silently ignored
- basename rail generalized: properties targets must end '.properties'
(was exact 'gradle.properties') — rc files/gitconfig still blocked;
EGB-531 wrong-basename test updated for the sanctioned change
- push syncs FROM the manifest; v1 store layout unchanged (nested
entries land at <project>/<relpath>.age, same shape -w always used)
- discovery (root globs + quiet package.json workspace re-scan when a
manifest exists) feeds the manifest as a generator; new files auto-add
with ==> notice + undo guidance
- options.autoAdd committed toggle (default ON when absent); explicit
false warns on undeclared files instead of enrolling them
- push --frozen: declared-only for one invocation; push --dry-run:
reports would-add/would-sync, touches nothing
- bootstrap ordering: manifest written only after >=1 blob encrypts
- declared-but-missing warns and continues; unsafe manifest path dies
- jq // falsy gotcha: explicit autoAdd:false compared directly