Summary
Thread an explicit list of files written during an akm improve run through to the end-of-run git auto-sync (saveGitStash), so the commit stages exactly the files the run modified — deterministic, rather than the current "stage everything under akm-managed dirs" heuristic.
Background
PR #651 fixed a production incident where end-of-run auto-sync refused to commit for ~1.5 days because stray non-akm files (tasks.bak-…, data.js, akm-health-report.html, reports/) in the stash root tripped the old all-or-nothing git add -A + refuse-guard. The fix replaced that with a scoped-staging precedence in saveGitStash (src/sources/providers/git.ts):
- Explicit list —
opts.paths?: string[] → git add -- <those> (chunked). (exposed, but no caller passes it yet)
- Managed pathspecs (default) —
git add -- <each TYPE_DIRS value> .akm (those that exist). This is what akm improve currently uses.
git add -A — last resort only.
The opts.paths parameter exists and is tested, but akm improve's sync call site (src/commands/improve/improve.ts, the saveGitStashFn(undefined, message, writableOverride, { push, repoDir }) call) passes undefined, so improve falls back to path 2.
Why this issue
Path 2 (managed-pathspec scoping) is correct and safe — it commits everything akm owns and never stages stray non-akm files. But it is coarse: it stages any dirty file under memories/, knowledge/, lessons/, facts/, etc., even ones a human edited out-of-band during the run, not just the files this improve run actually wrote. Threading the exact written-file set makes auto-sync deterministic and attributable: the commit contains precisely the run's accepted-proposal writes and nothing else.
Proposed work
- Collect written paths in the improve result. During a run, accumulate the repo-relative path of every file akm writes:
- accepted-proposal target files (reflect / distill / consolidate / extract / recombine / procedural promotions),
- memory-inference
.derived.md writes,
- any direct edits / schema-repair / lint-fix writes,
- removals (deletes) so they can be
git add -- (staged for deletion) too.
Expose as e.g. result.writtenPaths: string[] (deduped, repo-relative).
- Thread it into the sync call. Pass
{ paths: result.writtenPaths } into saveGitStash at the improve sync site, so precedence path 1 is used.
- Keep the managed-pathspec fallback for callers that don't/can't supply a list (e.g.
akm sync, akm push). Empty/undefined paths must still behave as today (path 2).
- Edge cases: if
writtenPaths is non-empty but a path was later reverted/removed by a downstream pass (e.g. proposal reverted, orphan purge), ensure the staged set reflects the final on-disk state (stage deletions; don't add a path that no longer exists without also handling the delete). Verify git diff --cached --quiet still short-circuits empty commits.
Acceptance criteria
- A run that writes files A, B under
memories/ while an unrelated human edit C also sits dirty under memories/ → the auto-sync commit contains only A and B, not C. (With managed-pathspec scoping today, C would be swept in.)
result.writtenPaths is populated and deduped; deletions handled.
akm sync / akm push (no explicit list) unchanged — still managed-pathspec scoped.
- Tests cover: written-list staging excludes unrelated managed-dir edits; deletions staged; empty list falls back to managed pathspecs; reverted/removed path handled.
References
Summary
Thread an explicit list of files written during an
akm improverun through to the end-of-run git auto-sync (saveGitStash), so the commit stages exactly the files the run modified — deterministic, rather than the current "stage everything under akm-managed dirs" heuristic.Background
PR #651 fixed a production incident where end-of-run auto-sync refused to commit for ~1.5 days because stray non-akm files (
tasks.bak-…,data.js,akm-health-report.html,reports/) in the stash root tripped the old all-or-nothinggit add -A+ refuse-guard. The fix replaced that with a scoped-staging precedence insaveGitStash(src/sources/providers/git.ts):opts.paths?: string[]→git add -- <those>(chunked). (exposed, but no caller passes it yet)git add -- <each TYPE_DIRS value> .akm(those that exist). This is whatakm improvecurrently uses.git add -A— last resort only.The
opts.pathsparameter exists and is tested, butakm improve's sync call site (src/commands/improve/improve.ts, thesaveGitStashFn(undefined, message, writableOverride, { push, repoDir })call) passesundefined, so improve falls back to path 2.Why this issue
Path 2 (managed-pathspec scoping) is correct and safe — it commits everything akm owns and never stages stray non-akm files. But it is coarse: it stages any dirty file under
memories/,knowledge/,lessons/,facts/, etc., even ones a human edited out-of-band during the run, not just the files this improve run actually wrote. Threading the exact written-file set makes auto-sync deterministic and attributable: the commit contains precisely the run's accepted-proposal writes and nothing else.Proposed work
.derived.mdwrites,git add --(staged for deletion) too.Expose as e.g.
result.writtenPaths: string[](deduped, repo-relative).{ paths: result.writtenPaths }intosaveGitStashat the improve sync site, so precedence path 1 is used.akm sync,akm push). Empty/undefinedpathsmust still behave as today (path 2).writtenPathsis non-empty but a path was later reverted/removed by a downstream pass (e.g. proposal reverted, orphan purge), ensure the staged set reflects the final on-disk state (stage deletions; don'tadda path that no longer exists without also handling the delete). Verifygit diff --cached --quietstill short-circuits empty commits.Acceptance criteria
memories/while an unrelated human edit C also sits dirty undermemories/→ the auto-sync commit contains only A and B, not C. (With managed-pathspec scoping today, C would be swept in.)result.writtenPathsis populated and deduped; deletions handled.akm sync/akm push(no explicit list) unchanged — still managed-pathspec scoped.References
src/sources/providers/git.ts—saveGitStash,opts.paths(added in fix(sync): scope auto-sync staging to akm paths instead of refusing on stray files #651)src/commands/improve/improve.ts— end-of-run sync call site (passesundefinedtoday)