From 1c7012a89e9804553177b11ad508105d11df5ba5 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste THERY Date: Sat, 18 Jul 2026 20:40:06 +0700 Subject: [PATCH] fix(core): distinguish upgrade readiness from advisories Release highlights: - keep retrieval ready after safe migrations when only privacy warnings remain Release details: - **Upgrade DX:** report security follow-ups as non-blocking advisories - **Continuity:** preserve strict doctor checks while avoiding unnecessary reindex loops Verification: - pass pnpm validate - verify both PAC indexes report current and ready with their advisories --- README.md | 4 +++- docs/api-reference.md | 2 ++ docs/cli-reference.md | 7 ++++-- docs/troubleshooting.md | 3 +++ packages/ragmir-core/README.md | 3 ++- packages/ragmir-core/src/cli.ts | 8 +++++++ packages/ragmir-core/src/upgrade.test.ts | 27 ++++++++++++++++++++++++ packages/ragmir-core/src/upgrade.ts | 8 +++++-- 8 files changed, 56 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a1102a9..5858273 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,9 @@ Run this after updating the package and before the first retrieval with the new agent helpers and stages any required rebuild in a separate generation. It never deletes the active index first: only a validated replacement activates, and interrupted or failed rebuilds remain resumable. A long-running host can keep its already loaded runtime serving the previous generation, -then restart or cut over after `status=current` and `ready=true`. +then restart or cut over after `status=current` and `ready=true`. Privacy or extractor warnings are +reported separately as `advisory` lines and do not mislabel an operational index as needing repair; +resolve them with `rgr security-audit` without discarding the working index. ### Semantic retrieval and scanned PDFs diff --git a/docs/api-reference.md b/docs/api-reference.md index 141e720..94a4ab4 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -129,6 +129,8 @@ peer-only, and changed paths plus recommended actions. It never includes source authoritative copy. `inspectUpgrade(cwd)` reports whether an index is current, missing, incompatible, or needs repair. +Its `ready` field covers upgrade and retrieval continuity; `privacyCompliant` and `advisories` +surface independent local security follow-ups without turning a compatible index into a repair. `upgradeProject({ cwd })` refreshes managed helpers and safely ingests or rebuilds before returning the final doctor report. Call it after updating the package and before accepting retrieval on the new runtime. Rebuild activation never deletes the previous validated generation first. A host that diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 366d030..12d8a02 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -100,7 +100,9 @@ rgr upgrade `upgrade --check` reports `current`, `index-required`, `rebuild-required`, or `repair-required`, including the version that wrote the active index. Run it after updating the package and before the first retrieval with the new runtime. Incompatible retrieval is refused with a direct `rgr upgrade` -instruction instead of reading an untrusted layout. +instruction instead of reading an untrusted layout. `ready` describes upgrade and retrieval +continuity. `privacyCompliant` and repeated `advisory` lines report separate security follow-ups; +they do not turn a compatible operational index into `repair-required`. `upgrade` refreshes managed agent helpers and performs any required ingest or rebuild. Schema, embedding, chunking, redaction, and index-policy changes use the staged-generation flow: Ragmir @@ -109,7 +111,8 @@ duplicate-ID validation activates. Failed or interrupted rebuilds never activate and can resume. Older configs that omit newer optional fields receive current safe defaults. `rgr doctor --fix` uses the same repair path. A long-running host can keep its already loaded runtime on the previous generation, then restart or cut over after the upgrade reports -`status=current` and `ready=true`. +`status=current` and `ready=true`. Address any advisory with `rgr security-audit` or +`rgr security-audit --strict`; deleting and rebuilding a healthy index is not required. ## Resumable ingestion diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index aba5fd4..87b6427 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -90,6 +90,9 @@ activates. If the process is interrupted, rerun the command to resume; do not de `.ragmir/storage/` first. A long-running host can keep its already loaded runtime serving during the rebuild, then restart or cut over once the upgrade reports `status=current` and `ready=true`. Use `rgr doctor --fix` for the same repair flow when setup or agent helpers also need attention. +`privacyCompliant=false` and `advisory=...` can accompany `status=current`: retrieval is compatible, +but a separate local security control still needs review. Run `rgr security-audit` for the exact +follow-up instead of deleting a healthy index. ## Strict audit fails diff --git a/packages/ragmir-core/README.md b/packages/ragmir-core/README.md index 49fc5a2..43ecf0c 100644 --- a/packages/ragmir-core/README.md +++ b/packages/ragmir-core/README.md @@ -86,7 +86,8 @@ Top-level `ingest`, `search`, `ask`, and `research` functions remain available f - `rgr team snapshot` and `rgr team compare` explain configuration and per-file drift without sharing source text or guessing which copy is authoritative. - After a package update, `rgr upgrade --check` previews compatibility; `rgr upgrade` safely stages - any required rebuild without deleting the active index first. + any required rebuild without deleting the active index first. Privacy warnings remain visible as + non-blocking advisories and can be handled separately with `rgr security-audit`. The [CLI reference](https://github.com/jcode-works/jcode-ragmir/blob/main/docs/cli-reference.md), [API reference](https://github.com/jcode-works/jcode-ragmir/blob/main/docs/api-reference.md), and diff --git a/packages/ragmir-core/src/cli.ts b/packages/ragmir-core/src/cli.ts index 0967646..4235b42 100644 --- a/packages/ragmir-core/src/cli.ts +++ b/packages/ragmir-core/src/cli.ts @@ -310,10 +310,14 @@ program `indexedWithRagmirVersion=${inspection.indexedWithRagmirVersion ?? "unavailable"}`, ) console.log(`ready=${inspection.ready}`) + console.log(`privacyCompliant=${inspection.privacyCompliant}`) console.log(`safeActivation=${inspection.safeActivation}`) if (inspection.reason) { console.log(`reason=${inspection.reason}`) } + for (const advisory of inspection.advisories) { + console.log(`advisory=${advisory}`) + } return } @@ -329,6 +333,7 @@ program console.log(`runtimeRagmirVersion=${result.runtimeRagmirVersion}`) console.log(`indexedWithRagmirVersion=${result.indexedWithRagmirVersion ?? "unavailable"}`) console.log(`ready=${result.ready}`) + console.log(`privacyCompliant=${result.privacyCompliant}`) console.log(`safeActivation=${result.safeActivation}`) console.log(`action=${result.action}`) console.log( @@ -338,6 +343,9 @@ program if (result.reason) { console.log(`reason=${result.reason}`) } + for (const advisory of result.advisories) { + console.log(`advisory=${advisory}`) + } if (!result.ready) { process.exitCode = 1 } diff --git a/packages/ragmir-core/src/upgrade.test.ts b/packages/ragmir-core/src/upgrade.test.ts index 4eb4b16..49b61a2 100644 --- a/packages/ragmir-core/src/upgrade.test.ts +++ b/packages/ragmir-core/src/upgrade.test.ts @@ -78,6 +78,33 @@ describe("upgrade continuity", () => { }) }, 20_000) + it("should report privacy warnings as non-blocking upgrade advisories", async () => { + const root = await upgradeFixture() + const config = await loadConfig(root) + const currentManifest = await readIndexManifest(config) + if (!currentManifest?.health) { + throw new Error("Expected an index health snapshot.") + } + const warning = "A configured local extractor executes with operator authority." + await writeIndexManifest( + { + ...currentManifest, + health: { ...currentManifest.health, securityWarnings: [warning] }, + }, + config, + currentManifest.indexedFiles, + ) + + await expect(inspectUpgrade(root)).resolves.toMatchObject({ + status: "current", + ready: true, + privacyCompliant: false, + advisories: [warning], + reason: null, + }) + await expect(search("continuity", { cwd: root })).resolves.toHaveLength(1) + }, 20_000) + it("should stage a rebuild when an old index has no compatible manifest", async () => { const root = await upgradeFixture() const config = await loadConfig(root) diff --git a/packages/ragmir-core/src/upgrade.ts b/packages/ragmir-core/src/upgrade.ts index e8e13c4..54f91f1 100644 --- a/packages/ragmir-core/src/upgrade.ts +++ b/packages/ragmir-core/src/upgrade.ts @@ -13,6 +13,8 @@ export interface UpgradeInspection { runtimeRagmirVersion: string indexedWithRagmirVersion: string | null ready: boolean + privacyCompliant: boolean + advisories: string[] reason: string | null recommendedCommand: "rgr upgrade" safeActivation: boolean @@ -42,7 +44,9 @@ export async function inspectUpgrade(cwd = process.cwd()): Promise