Skip to content

Auto-resolve a runtime-category farm collision instead of asking - #18

Merged
Mearman merged 2 commits into
mainfrom
feat/auto-resolve-runtime-collisions
Sep 12, 2026
Merged

Mearman merged 2 commits into
mainfrom
feat/auto-resolve-runtime-collisions

Conversation

@Mearman

@Mearman Mearman commented Sep 12, 2026

Copy link
Copy Markdown
Member

Every retained superseded farm on a real, long-lived install (this session found 24 of them across 4 identities) collided on the same handful of names: .last-update-result.json, mcp-needs-auth-cache.json, .last-cleanup, cache, shell-snapshots. Every one of those classifies as runtime, whose own definition (the README category table) is specifically live per-process or per-machine artifacts a swap has no business fighting over. Leaving them for identity resolve to ask about turned a single crashed launch into a standing manual chore that had to be run identity by identity.

carryOver now classifies a colliding name before reporting it. A runtime-category collision discards the old copy and keeps whatever the current farm already has — no data moved, no prompt. This only needs the name's static classification, never the resolved shared/not-shared decision for the directory, since a runtime entry is disposable whether or not this identity currently chooses to share it. Every other category is unaffected: a genuine collision (settings, knowledge, history, an unclassified name) still retains the superseded farm and still asks, exactly as before.

Threaded through both places a collision can surface — the automatic crash-recovery path that runs on every launch (recoverFarm, which runs before identity.json is even read; it gets classification from FarmRuntime, which is identity-independent and already available at that point), and the interactive identity resolve command. Both report what was auto-resolved, distinctly from anything still needing a human decision.

Also extracted loadClassification (config/classify.ts) since cli.ts, check.ts, and configure.ts were each independently repeating the identical read-defaults-plus-overlay block — a fourth copy for identity resolve would have made it four.

Ran the built CLI against this machine's own real ~/.claude-use (24 retained farms, 4 identities) as an end-to-end check before opening this: every one auto-resolved with no prompt, all named .last-update-result.json/mcp-needs-auth-cache.json/.last-cleanup/cache/shell-snapshots, doctor still reports every identity healthy afterward.

cli.ts, check.ts, and configure.ts each independently read
categories.default.json, parsed it against CategoryClassificationSchema,
read categories.local.json, and merged the two into the same
{ defaults, overlay? } shape — three copies of a validation step that
never varies between them, so a fourth call site (added next) would
have made it four.

loadClassification centralises this in config/classify.ts, next to the
classification domain logic it feeds, rather than as a generic
config/store.ts helper: everywhere else classification is used already
imports from this file. Each of the three sites drops its own
categories.default.json import, CategoryClassificationSchema/
CategoryClassificationOverlaySchema imports, and (where nothing else in
the file needed it) its own readJson import.
Every retained superseded farm found on a real, long-lived install
collided on the same handful of names: .last-update-result.json,
mcp-needs-auth-cache.json, .last-cleanup, cache, shell-snapshots. Every
one of them classifies as runtime, whose own definition (see the README
category table) is specifically live per-process or per-machine
artifacts a swap has no business fighting over. Leaving them for
`identity resolve` to ask about, one login at a time, turned a single
crashed launch into a standing manual chore.

carryOver now classifies a colliding name before reporting it. A
runtime-category collision discards the old copy and keeps whatever the
current farm already has, with no data moved and no callback invoked —
this needs only the name's static classification, never the resolved
shared/not-shared decision for the directory, since a runtime entry is
disposable whether or not this identity currently chooses to share it.
Every other category is unaffected: a genuine collision (settings,
knowledge, history, an unclassified name) still retains the superseded
farm and still asks.

Threaded through both places a collision can surface. The automatic
crash-recovery path (recoverFarm, called before identity.json is even
read) gets classification from FarmRuntime, which is identity-independent
and already available at that point. The interactive `identity resolve`
command loads it the same way every other command now does.

recoveryDiagnostics and identity resolve's own console output both name
what was auto-resolved, distinctly from what still needs
`identity resolve`, so the behaviour stays visible rather than silent.
@Mearman
Mearman marked this pull request as ready for review September 12, 2026 07:16
@Mearman
Mearman merged commit 3b7d3ee into main Sep 12, 2026
31 checks passed
@Mearman
Mearman deleted the feat/auto-resolve-runtime-collisions branch September 12, 2026 07:16
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-12T07:25:12.320015Z af0a281 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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