# Mode: update — Interactive System Update When the user runs `/career-ops update`, execute this interactive update flow. ## Step 1 — Check for Updates Run `node update-system.mjs check --force` and parse the JSON output. `--force` because the user asked: a release they said no to earlier is shown too. - If `up-to-date`: Tell the user "career-ops is up to date (v{version})." and stop. - If `offline`: Tell the user "Cannot reach GitHub to check for updates. Try again later." and stop. If the JSON carries a `detail` field, show it verbatim after that sentence: it is a fixed-English diagnostic naming what failed (for example `ENOENT` when curl is not installed, or a proxy or TLS error), and that is what the user needs to fix it. - If `no-remote-version`: Tell the user "Couldn't determine the latest career-ops release right now. Try again later." and stop. - If `update-available`: Continue to Step 2. ## Step 2 — Show What Changed Show the user what will change: the release `apply` installs, `career-ops-v{remote}`, not `main`. Run: ```bash git fetch https://github.com/career-ops-hq/career-ops.git career-ops-v{remote} || { echo "Failed to fetch latest changes. Cannot generate an accurate diff preview." exit 1 } ``` If the fetch fails, stop Step 2 and tell the user you couldn't preview the changes — don't proceed with a stale `FETCH_HEAD`. Then, only if the fetch succeeded, for each System Layer file category show a summary: ```bash git diff HEAD..FETCH_HEAD --stat -- modes/ CLAUDE.md AGENTS.md *.mjs batch/ dashboard/ templates/ docs/ VERSION DATA_CONTRACT.md ``` Present to the user as a clear summary: > **Update available: v{local} → v{remote}** > > **Changes summary:** > - Modes: {N} files changed (list which ones) > - Scripts: {N} files changed > - Dashboard: {N} files changed > - Templates: {N} files changed > - Other: {N} files changed > > **Changelog:** > [Render in {language.output}: {changelog from update-system.mjs check output}] > > Your personal files (CV, profile, tracker, reports) will NOT be touched. `changelog` can come back empty, either because the release carries no notes or because the check resolved the version without reading the releases API. Do not render the **Changelog:** line when that happens — a lone `> **Changelog:**` with nothing under it reads as a failure, and nothing failed. Use this in place of those two lines: > **Changelog:** not available for v{remote}. The release notes are at https://github.com/career-ops-hq/career-ops/releases If the user wants details on specific files, show the actual diff for those files using `git diff HEAD..FETCH_HEAD -- {path}`. ## Step 3 — Compatibility Check Before applying, check if the update might affect the user's customizations: 1. **Read `modes/_profile.md`** (if it exists) 2. **Diff `modes/_shared.md`**: Run `git diff HEAD..FETCH_HEAD -- modes/_shared.md` 3. **Check for archetype changes**: If `_shared.md` has changes in the "Archetype Detection" section, and `_profile.md` references archetype names, warn the user: > "⚠️ The scoring system or archetypes were updated. Your customizations in `_profile.md` may reference outdated archetype names. I'll review them after the update." 4. **Check for scoring changes**: If the "Scoring System" section changed, note it: > "ℹ️ The scoring system was updated. Scores in future evaluations may differ slightly from previous ones." 5. **Check for new mode files**: If new modes were added (files in `modes/` that don't exist locally), mention them: > "✨ New modes available: {list}. Run `/career-ops` to see all commands." ## Step 4 — Confirm and Apply Ask the user for confirmation: > "Ready to update. Apply changes? (This can be rolled back with `/career-ops update rollback`)" If yes: 1. Capture the current commit as a run-specific pre-update baseline before apply runs, e.g. `PRE_UPDATE_REF=$(git rev-parse HEAD)`. Don't rely on `backup-pre-update-{local}` alone — `update-system.mjs apply` reuses that branch if it already exists, so it may point at an older snapshot. 2. **Save local CLAUDE.md additions.** CLAUDE.md is a system file. When this install has changed it, `apply` keeps the local version by default: it lists CLAUDE.md under "Keeping your versions" and writes `CLAUDE.md.bak`. It replaces CLAUDE.md with the two-line template (`@AGENTS.md` + the local-additions comment) only with `--force`, or when it does not see the change as a local edit. Before applying, read the current CLAUDE.md and save everything after that two-line header, so step 4 can put it back if apply replaced the file. If CLAUDE.md has nothing beyond the two-line header, note that there is nothing to restore. 3. Run `node update-system.mjs apply --confirm`, capturing its exit code without stopping on failure yet — the restore in step 4 must run either way. The `--confirm` flag is required so scheduled checks can never install files silently. 4. **Restore local CLAUDE.md additions if apply removed them**, whether step 3 succeeded or failed. Re-read CLAUDE.md. If the content saved in step 2 is still in it, which is the default because `apply` kept your version, leave the file as it is: appending the content again would duplicate it, and every later update would add another copy. Only if the saved content is missing, append it after the two-line header. 5. Now check the exit code captured in step 3: - If non-zero, treat apply as failed. Show the captured output and offer: > "⚠️ Update apply failed. Want me to show the full error, or try `/career-ops update rollback`?" - Stop the flow here if apply failed — do not run doctor, verify-pipeline, or reconciliation on a partially-applied update. 6. Run `node doctor.mjs` to validate the installation. - If it exits with a non-zero code, treat validation as failed. Show the captured output and offer: > "⚠️ Validation failed after update. Want me to show the full error, or roll back with `/career-ops update rollback`?" - Stop the flow here if validation failed — do not run verify-pipeline, reconciliation, or show the success message. - Then run `node verify-pipeline.mjs` to check the data layer. Show its output, but treat it as informational only — never as a gate, and never with a rollback offer. Reason: unlike doctor, verify-pipeline also fails on pre-existing tracker issues that have nothing to do with this update (a non-canonical status, a moved report file, a duplicate row number) — rolling back the release fixes none of those. If it reports errors, note them separately (e.g. "verify-pipeline also flagged N pre-existing data issue(s) — unrelated to this update, worth a look separately") and continue to Step 7 regardless of its exit code. 7. If Step 3 flagged archetype/scoring changes, reconcile `modes/_profile.md` against the new `modes/_shared.md`: - Read both the pre-update version (`git show $PRE_UPDATE_REF:modes/_shared.md`) and the post-update version of `modes/_shared.md`. - Extract the canonical archetype identifiers from each version (archetype headings/definitions, plus any slug/alias fields). - Read `modes/_profile.md` and look for tokens that match archetype names (inline text, Markdown links, YAML keys, code spans). - Classify each reference: - **Unchanged**: exact match in the new `_shared.md` → no action. - **Renamed**: no exact match, but a single strong fuzzy match in the new `_shared.md` (e.g. Levenshtein similarity ≥ 0.7) → offer to rename. - **Removed**: no match at all → offer to delete or replace. - When a rename or removal is detected, ask before editing: - For renames: > "Your _profile.md references archetype '{old_name}' which was renamed to '{new_name}'. Want me to update it?" - For removals: > "Your _profile.md references archetype '{old_name}' which was removed in the new _shared.md. Want me to delete the reference or replace it with another archetype?" 8. Show final status: > "✅ Updated to v{version}. Run `node doctor.mjs` anytime to verify setup, or `node verify-pipeline.mjs` to check your data." If the updater printed `Update applied but NOT committed`, relay that complete block instead of the plain success line: include the staged state, all three recovery options and their exact commands, and the `--commit-on-branch` opt-in (#3846). If no: 1. Run `node update-system.mjs dismiss --version {remote}` 2. Tell the user they will be asked again when a newer release is out, and can run `/career-ops update` anytime to check again. ## Step 5 — Rollback (if requested) If the user says "rollback" or runs `/career-ops update rollback`: 1. Run `node update-system.mjs rollback` 2. Show what was restored. ## Rules - NEVER auto-modify User Layer files during update (cv.md, config/profile.yml, user files in data/, reports/, output/, interview-prep/, jds/, article-digest.md, portals.yml). The only exceptions are the exact system-owned `.gitkeep` scaffolds listed in `DATA_CONTRACT.md`; user files beside them remain unchanged. - `modes/_profile.md` is User Layer too: the compatibility check in Step 3 reads it strictly read-only - Exception: `modes/_profile.md` may be edited **only** in Step 4.7, and **only** after the user explicitly confirms each individual rename/removal. Never batch-edit without per-change consent. - User-specific customizations (archetypes, scoring weights, narrative) belong in `modes/_profile.md` or `config/profile.yml`, never in `modes/_shared.md` - CLAUDE.md's local additions (everything after the two-line `@AGENTS.md` header) MUST be saved before apply and checked immediately after — on both the success AND failure path (Step 4.2, Step 4.4). Restore them only when they are no longer in CLAUDE.md. `apply` keeps a CLAUDE.md this install changed unless `--force` is given, and appending the saved content to a file that still has it duplicates the additions on every update. - After a successful apply, `node hired-share.mjs --status` may report a hire that was never asked about, or one marked "later" more than 30 days ago. That earns **at most ONE** gentle mention of the Hired Wall, then the answer is respected — never a scheduled reminder. Cadence and wording: `AGENTS.md` → "Celebrating a hire (the Hired Wall)". - Never trim the staged-but-uncommitted notice or its recovery commands (Step 4.8). - If anything goes wrong, tell the user to run `node update-system.mjs rollback` - Keep the output concise — users don't want walls of text during an update