You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
add a shared versioned AES-256-GCM envelope for content-bearing secondary IndexedDB records
encrypt scene revisions, AI inference results, ProForge memory/history, cross-project metadata/embeddings, and LoRA metadata/datasets/training runs
fail closed while configured storage is locked, reject corrupt envelopes, and lazily migrate legacy plaintext after unlock
document the accepted DuckDB structural-metadata and large LoRA weight-blob exceptions
correct project documentation so cross-database passphrase rotation is tracked as a durable resumable follow-up, not described as atomic
Verification
pnpm run lint
pnpm run typecheck
pnpm run i18n:check (19 locales, 2,869 keys)
pnpm run parity:check
pnpm run docs:check
pnpm run suppressions:check (52/52)
pnpm run token:audit (160/160)
targeted Vitest: 109 existing/new secondary-store tests from the first commit
targeted Vitest: 53 Cross-Project/LoRA tests from the second commit
Security boundary
Large LoRA weight blobs remain outside the manuscript-data guarantee. DuckDB structural analytics metadata remains an accepted plaintext boundary; literal codex_mentions.excerpt encryption is unchanged. Durable resumable passphrase rotation across independent databases is intentionally deferred to the next isolated security change.
Your recent review volume is higher than typical usage, so adaptive limits are currently applied.
Next review available in:29 minutes
Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).
How can I continue?
After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.
To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.
How do review limits work?
CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.
For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.
We reviewed changes in 804793a...0898f6a on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.
Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
`isSecureRecordCandidate` has a cyclomatic complexity of 6 with "medium" risk
A function with high cyclomatic complexity can be hard to understand and
maintain. Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A higher cyclomatic complexity indicates
that the function has more decision points and is more complex.
The reason will be displayed to describe this comment to others. Learn more.
Gate destructive writes while the encryption key is locked
When a user locks the session and then deletes a LoRA adapter, scene revision, project index, or memory entry, deleteAdapter, deleteRevision, removeProjectIndex, and deleteMemoryEntry issue raw IndexedDB deletes without passing through this configured-storage check, so destructive writes still succeed while the secondary stores are supposedly locked. Apply the same sentinel/key guard before these delete transactions to prevent irreversible data loss while locked.
The reason will be displayed to describe this comment to others. Learn more.
Treat partial secure envelopes as corruption
If an encrypted payload loses any one envelope field—for example, a missing ciphertext property—this predicate returns false. While the key is unlocked, readSecureRecordPayload consequently accepts the malformed object as legacy plaintext, and several callers spread and lazily rewrite it, potentially returning records without their required content and persisting that damage instead of raising SecureRecordCorruptError. Treat the presence of the version marker or any envelope field as a candidate, then validate the complete shape.
The reason will be displayed to describe this comment to others. Learn more.
Decrypt secondary records before disabling encryption
After a user enables encryption and writes any of these new secondary envelopes, the existing Settings disable flow verifies the passphrase and then calls clearIdbPassphrase(), which removes both the sentinel and active key without decrypting these databases. Subsequent reads still enter this envelope branch and always throw SecureRecordLockedError, while the disabled feature flag prevents the startup unlock modal from appearing, so revisions, ProForge history, search metadata, and LoRA records become inaccessible through the normal UI. The disable operation must rewrite secondary envelopes to plaintext before clearing the key and sentinel.
The reason will be displayed to describe this comment to others. Learn more.
Bind encrypted payloads to their routing fields
Because encryption receives only the payload, the AES-GCM authentication tag is not bound to the plaintext record ID, project ID, scene ID, or timestamps stored alongside it. Swapping two valid payload envelopes in IndexedDB therefore decrypts successfully and silently associates one project's or scene's content with another record instead of reporting corruption. Pass canonical routing fields as AES-GCM additionalData during encryption and require the same data during decryption.
The reason will be displayed to describe this comment to others. Learn more.
Preserve Blob artifacts when encrypting run history
When an encrypted ProForge run includes the production stage, its agentOutput contains a ProductionManifest whose artifacts carry generated PDF, EPUB, and Markdown Blob values. prepareSecureRecordPayload serializes this entire history through JSON.stringify, which converts each Blob to {}; after reload the decrypted history therefore contains invalid artifact objects and the generated files are silently lost, whereas the previous IndexedDB structured-clone write preserved them. Encode Blob bytes and MIME types explicitly or use a serialization format that supports structured-clone values.
Handoff — paused to conserve the remaining weekly agent budget
Current head: 0898f6a4 (25 changed files). This PR is intentionally Draft and must not merge yet.
Completed
Shared versioned AES-256-GCM secondary-record envelope with typed locked/corrupt failures.
Scene revisions, AI inference cache, ProForge memory/history, cross-project metadata/embeddings, and LoRA metadata/datasets/training records integrated.
Legacy plaintext lazy migration and raw-IDB canary coverage added.
Security boundary/docs reconciled; DuckDB structural metadata and large LoRA weight blobs remain explicit exceptions.
Follow-up 0898f6a4 fixes malformed/incomplete envelope fall-through; 46/46 focused storage-encryption tests and lint are green.
Earlier local gates were green: lint, typecheck, i18n (19 × 2,869), parity, docs, suppressions 52/52, tokens 160/160; targeted store tests were green.
Release blocker
Copilot correctly identified that the live passphrase-change and encryption-disable flows do not migrate/decrypt the new secondary envelopes. Changing the passphrase replaces the active verifier/key after only primary app-data/snapshot migration; disabling deletes the verifier. Either operation can strand secondary records under the old key. See #310 (comment).
Before marking ready, choose and test one safe path:
Preferred: implement the durable resumable cross-database rotation journal already specified in docs/IDB-ENCRYPTION.md, and make disable decrypt/migrate every registered secondary store before removing the verifier; or
Minimal interim safety: block passphrase change and disable in both UI and service-level APIs while secondary encryption is present, with honest user-facing copy, until the journal ships.
Also test interruption/restart, wrong old/new passphrase, mixed old/new records, failure before verifier replacement, and disable recovery. Do not merely hide UI controls while callable service paths remain destructive.
Reviews / CI
CodeRabbit auto-triggered but was rate-limited (no code review); retry after the cooldown shown by its PR note.
Copilot produced two findings: the rotation/disable blocker above remains open; incomplete-envelope fall-through is fixed by 0898f6a4 and its thread is now outdated.
DeepSource generated ~126 mostly identical Unexpected function declaration in the global scope findings against normal TypeScript ES modules, plus minor complexity notices. Treat the module-scope reports as analyzer/configuration false positives; do not wrap the codebase in IIFEs. They still need evidence replies/resolution when work resumes.
Cloud CI restarted for 0898f6a4 and was still pending at pause time. Recheck every required job and all paginated review threads before ready/merge.
Resume order
Resolve the passphrase rotation/disable blocker with tests.
Run only targeted local Vitest plus sequential quick gates.
Push; inspect CI artifacts and all 128+ paginated review threads.
Reply/resolve each valid or false-positive thread with evidence; retry CodeRabbit after its cooldown and repeat until a fresh review yields zero new comments.
Mark ready only when CI is green and unresolved thread count is zero. Merge via the already authorized admin bypass only then.
Do not cut a release from this draft. A future v1.27.0 boundary is appropriate only after rotation and durable-log hardening are complete.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verification
pnpm run lintpnpm run typecheckpnpm run i18n:check(19 locales, 2,869 keys)pnpm run parity:checkpnpm run docs:checkpnpm run suppressions:check(52/52)pnpm run token:audit(160/160)Security boundary
Large LoRA weight blobs remain outside the manuscript-data guarantee. DuckDB structural analytics metadata remains an accepted plaintext boundary; literal
codex_mentions.excerptencryption is unchanged. Durable resumable passphrase rotation across independent databases is intentionally deferred to the next isolated security change.