Skip to content

feat(core): worldscript-project crate — Wave 2 first slice - #409

Merged
qnbs merged 9 commits into
mainfrom
feat/wave2-worldscript-project-crate
Aug 20, 2026
Merged

feat(core): worldscript-project crate — Wave 2 first slice#409
qnbs merged 9 commits into
mainfrom
feat/wave2-worldscript-project-crate

Conversation

@qnbs

@qnbs qnbs commented Aug 20, 2026

Copy link
Copy Markdown
Owner

User description

Summary

First substantive Wave 2 slice ("Rust Core extraction and headless harness") per docs/native/ROADMAP-QT-GPUI-DESKTOP.md. Follows PR #408, merged, which corrected a factual overstatement about desktop fs-encryption so this work wasn't designed against a false premise.

  • docs/native/CORE-MIGRATION-LEDGER.md — the capability-priority table backing every scope decision below: project schema/validation/plain-fs-I/O first; storage-IDB (all encryption) deferred to Wave 3-4; AI services out of scope for all of Wave 2.
  • New independent Cargo workspace (crates/Cargo.toml) — deliberately not unified with src-tauri/Cargo.toml. Verified two concrete reasons: .gitignore only covers src-tauri/target/, not a repo-root target/; and ci.yml's rust-tauri job hard-scopes its cache/working-directory to src-tauri/**. Unifying now risks both for zero benefit.
  • crates/worldscript-project/ — renderer-neutral project schema (schema.rs, plain Vec<T> where types.ts has Character[] | EntityState<Character, string> — the Redux coupling designed away), validation (validate.rs), a minimal versioned-migration mechanism (migrate.rs, one synthetic v1→v2 migration proving it), and plain JSON load/save (io.rs, no compression/atomicity — that's Wave 3). Zero dependencies beyond serde/serde_json.
  • Headless proof: cargo test (9 tests: full lifecycle round-trip, schema migration, corrupt/missing-field rejection without panicking, duplicate-ID validation) and cargo run --bin wsproj -- demo-lifecycle (CLI), both with zero GUI/Tauri dependency in cargo tree — satisfies Wave 2's stated exit criterion.
  • Golden-master fixture parity: tests/fixtures/project-golden-masters/*.json (5 fixtures — empty/typical/large-stress/missing-required-field/truncated) read from both tests/unit/projectGoldenMasters.test.ts (freezes current services/projectImportSchema.ts Zod behavior) and crates/worldscript-project/tests/fixtures_test.rs (asserts identical accept/reject verdicts on the same bytes) — a cross-language oracle without either side reading the other's code.
  • CI: new core-rust job (fmt/check/clippy/test on crates/, no GTK/WebKit deps needed — a concrete, checked-in proof of "no GUI runtime"), gated by a new changes.outputs.crates path filter, added to ci-success's required-job list (skip-is-pass, same pattern as rust-tauri).
  • Roadmap Wave 2 status: PLANNEDIN PROGRESS (not complete — task orchestration, storage-backend parity, diagnostics, and AI request model are all still deferred per the ledger). Also split G1's conflated "project/storage/crypto/migration headless APIs exist" checklist line, since only the project part is done.
  • .gitignore: added crates/target/ (caught a real mistake — I'd initially staged ~795 build-artifact files before catching this).
  • biome.json: excluded crates/ and the fixtures directory (the truncated.json fixture is intentionally invalid JSON — Biome was correctly flagging it as a parse error before the exclusion).

What this PR does NOT do

No encryption. No touching services/storage/* (IDB) or services/fs/* (beyond reading it for reference). No packages/worker-bus or task_supervisor.rs changes. No services/ai/* work. No changes to lora.rs/pandoc.rs. No Qt/GPUI code. No unifying the two Cargo workspaces. No wiring any Tauri command to this crate yet (deferred, optional fast-follow per the plan).

Test plan

  • cargo test --locked in crates/: 9/9 pass
  • cargo run --bin wsproj -- demo-lifecycle: succeeds
  • cargo clippy --locked --all-targets -- -D warnings: clean
  • cargo fmt --check: clean
  • cargo tree: confirms zero GUI/Tauri dependencies
  • pnpm exec vitest run tests/unit/projectGoldenMasters.test.ts: 5/5 pass, matches Rust fixture-test verdicts
  • pnpm run lint, pnpm run typecheck, pnpm run i18n:check, node scripts/check-doc-metrics.mjs, pnpm run guardrail:desktop-imports: all clean
  • node scripts/check-suppressions.mjs, pnpm run token:audit: both clean (ran before this machine's resource constraints required deferring the rest to CI, per this repo's own cloud-first-CI policy)
  • 23 files changed — well under the ~100-file review-bot threshold
  • CI green (required + advisory jobs) before merge, per repo policy

🤖 Generated with Claude Code

Summary by Sourcery

Establish the first headless Rust Core slice for validated, versioned WorldScript project files and integrate it into cross-language testing and CI.

New Features:

  • Add a renderer-independent Rust project core with schema modeling, structural validation, versioned migrations, and plain JSON file I/O.
  • Provide a headless wsproj demo-lifecycle CLI for project creation, validation, persistence, reload, migration, and revalidation.
  • Add shared TypeScript/Rust golden-master fixtures to verify compatible project-file acceptance and rejection behavior.

Enhancements:

  • Establish an independent Cargo workspace for the renderer-neutral core without GUI or Tauri dependencies.
  • Reject duplicate record IDs and unsupported future schema versions with structured errors.

Build:

  • Add Cargo dependency management for the new crates/ workspace and configure repository tooling for its artifacts and fixtures.

CI:

  • Add path-scoped Core Rust formatting, compilation, Clippy, and test checks to CI and require the gate when relevant files change.
  • Include the new Rust lockfile in OSV vulnerability scanning and add weekly Dependabot updates for the crates workspace.

Documentation:

  • Document the Wave 2 migration priorities and record the first slice as in progress in the native desktop roadmap.
  • Add a capability migration ledger clarifying completed, deferred, and out-of-scope native extraction work.

Tests:

  • Add Rust lifecycle, migration, validation, error-handling, and fixture-parity tests.
  • Add TypeScript golden-master tests covering accepted, rejected, and malformed project fixtures.

Chores:

  • Update contributor guidance for validating single-line QNBS-v3 comments.

CodeAnt-AI Description

Add a headless project core for validated, versioned JSON project files

What Changed

  • Adds a renderer-independent project model covering characters, worlds, and manuscript sections, with plain JSON load/save and structured errors for corrupt or incomplete files
  • Validates duplicate character, world, and manuscript IDs before projects are accepted
  • Supports upgrading older schema version 1 projects to the current version without losing existing content
  • Adds a command-line lifecycle demo that creates, validates, saves, reloads, migrates, and revalidates a project without a GUI runtime
  • Adds shared golden-master fixtures to verify that TypeScript and Rust accept and reject the same project files
  • Adds CI checks that run formatting, compilation, linting, and tests for the new Rust project core when its files change

Impact

✅ Headless project lifecycle
✅ Safer project imports with clear parse failures
✅ Preserved data when upgrading older project files

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • New Features

    • Added a structured project format for characters, worlds, timelines, and manuscript sections.
    • Added versioned project files with migration support and rejection of unsupported future versions.
    • Added JSON project import and export with readable error messages.
    • Added validation to detect duplicate record IDs.
    • Added a headless command-line workflow for creating, validating, saving, and migrating projects.
  • Tests

    • Added coverage for fixtures, round trips, migrations, invalid files, and large projects.
  • Chores

    • Added dedicated Rust workspace checks to continuous integration.

qnbs and others added 4 commits August 20, 2026 08:51
New independent Cargo workspace (crates/Cargo.toml) - deliberately
not unified with src-tauri/Cargo.toml, since a root-level workspace
would move build output to <repo-root>/target/ (not covered by
.gitignore's src-tauri/target/-only entry) and risks breaking the
rust-tauri CI job's path-scoped cache/working-directory assumptions.
See docs/native/CORE-MIGRATION-LEDGER.md.

crates/worldscript-project implements the highest-priority capability
from the ledger: renderer-neutral project schema, validation, a
minimal versioned-migration mechanism, and plain JSON load/save.
schema.rs uses plain Vec<T> where types.ts has Character[] |
EntityState<Character, string> - the Redux Toolkit coupling designed
away at the Rust layer. Zero dependencies beyond serde/serde_json.

Proven headless (no GUI/Tauri dependency in cargo tree):
- cargo test: 9 tests (lifecycle round-trip, schema migration,
  corrupt/missing-field rejection, duplicate-ID validation)
- cargo run --bin wsproj -- demo-lifecycle: CLI proof

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Shared fixtures (tests/fixtures/project-golden-masters/) referenced
from both tests/unit/projectGoldenMasters.test.ts (freezes current
Zod accept/reject behavior in services/projectImportSchema.ts) and
crates/worldscript-project/tests/fixtures_test.rs (asserts identical
verdicts on the same bytes) - a cross-language oracle without the two
implementations sharing code, per the Core-migration test policy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New changes.outputs.crates path filter (matches crates/**, same
pattern as the existing tauri output) and a core-rust job mirroring
rust-tauri's fmt/check/clippy/test steps - without the GTK/WebKit
apt-get install steps, since crates/worldscript-project has zero
GUI/Tauri dependencies. Added to ci-success's required-job list,
skip-is-pass, same as rust-tauri.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New docs/native/CORE-MIGRATION-LEDGER.md - the capability-priority
table backing this slice's scope decisions (project schema/validation/
plain fs I/O first; storage-IDB/encryption deferred to Wave 3-4;
AI services out of scope for all of Wave 2).

Updates the roadmap's Wave 2 section from PLANNED to IN PROGRESS with
a checklist reflecting what this slice actually covers, and splits
G1's conflated "project/storage/crypto/migration headless APIs exist"
line so partial progress (project done, storage/crypto still pending)
isn't misrepresented as complete.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@codeant-ai

codeant-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 04526a0 Aug 20, 2026 · 06:53 06:58

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @qnbs, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@codeant-ai

codeant-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldscript-studio Ready Ready Preview Aug 20, 2026 7:28am

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in: 28 minutes

Limit details: You’ve used all 2 included reviews currently available. Your 59 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

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?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e11de558-b1bd-4b85-a8d9-fd0736ab05b5

📥 Commits

Reviewing files that changed from the base of the PR and between 0eed529 and f728850.

📒 Files selected for processing (10)
  • .github/dependabot.yml
  • .github/workflows/ci.yml
  • CLAUDE.md
  • crates/worldscript-project/src/bin/wsproj.rs
  • crates/worldscript-project/src/migrate.rs
  • crates/worldscript-project/src/schema.rs
  • crates/worldscript-project/tests/fixtures_test.rs
  • crates/worldscript-project/tests/lifecycle_test.rs
  • tests/fixtures/project-golden-masters/typical-project.json
  • tests/unit/projectGoldenMasters.test.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a2a8337-df98-46f1-8db6-ca7d740186af

📥 Commits

Reviewing files that changed from the base of the PR and between ae037a0 and 0eed529.

📒 Files selected for processing (3)
  • crates/worldscript-project/src/migrate.rs
  • crates/worldscript-project/src/schema.rs
  • crates/worldscript-project/tests/lifecycle_test.rs

Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.


📝 Walkthrough

Walkthrough

This PR adds a Rust workspace with the worldscript-project crate. It defines project schemas, validation, versioned migration, JSON I/O, a headless CLI lifecycle, shared fixtures, tests, documentation, and path-scoped Rust CI.

Changes

Rust project core

Layer / File(s) Summary
Project schema and validation
crates/Cargo.toml, crates/worldscript-project/Cargo.toml, crates/worldscript-project/src/schema.rs, crates/worldscript-project/src/envelope.rs, crates/worldscript-project/src/validate.rs, crates/worldscript-project/src/lib.rs
The crate defines serialized project entities, versioned envelopes, duplicate-ID validation, parsing errors, and public re-exports.
Migration, persistence, and CLI lifecycle
crates/worldscript-project/src/migrate.rs, crates/worldscript-project/src/io.rs, crates/worldscript-project/src/bin/wsproj.rs
The crate migrates v1 envelopes to v2, rejects future schema versions, loads and saves JSON files, and runs a headless demo lifecycle with validation and round-trip checks.
Lifecycle and fixture validation
crates/worldscript-project/tests/*, tests/fixtures/project-golden-masters/*, tests/unit/projectGoldenMasters.test.ts
Rust and TypeScript tests cover accepted fixtures, malformed input, lifecycle persistence, migration, validation, default values, and large project data.
Workspace CI and project tracking
.github/workflows/ci.yml, .gitignore, biome.json, docs/native/CORE-MIGRATION-LEDGER.md, docs/native/ROADMAP-QT-GPUI-DESKTOP.md
CI detects crates changes and runs core-Rust checks. Tooling excludes Rust outputs and fixtures. Native migration and roadmap documents record the implemented project slice.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟡 Moderate · up to 0eed5

The PR adds versioned project loading and migration, but the current migration loop can hang when a migration fails to advance the schema version. Additional bounded migration-demo, fixture, and repository-format issues remain unresolved, so merge should wait for these fixes.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as wsproj
  participant Envelope as ProjectEnvelope
  participant IO as project I/O
  participant Migration as migrate_to_latest
  CLI->>Envelope: construct sample project
  CLI->>IO: save_project
  CLI->>IO: load_project
  IO-->>CLI: return parsed envelope
  CLI->>Migration: migrate_to_latest
  Migration-->>CLI: return migrated envelope
  CLI->>IO: save and reload migrated project
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 84.85% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the new worldscript-project Rust crate and its Wave 2 first-slice scope.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wave2-worldscript-project-crate

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Reviewer's Guide

Introduces a new independent Rust Cargo workspace with a worldscript-project crate that defines a renderer-neutral project schema plus validation, migration, and plain JSON I/O, wires golden-master fixtures for cross-language parity tests, adds a headless CLI/test harness, and extends CI with a path-scoped Rust core job while updating roadmap/docs and tooling config accordingly.

Sequence diagram for wsproj demo-lifecycle headless run

sequenceDiagram
actor User
participant wsproj
participant StoryProject
participant validate
participant ProjectEnvelope
participant io
participant migrate

User->>wsproj: demo-lifecycle
wsproj->>StoryProject: new("Demo Project", "A logline for the demo.")
wsproj->>validate: validate(&project)
wsproj->>ProjectEnvelope: current(project)
wsproj->>io: save_project(path, &envelope)
wsproj->>io: load_project(path)
io-->>wsproj: ProjectEnvelope
wsproj->>migrate: migrate_to_latest(envelope)
migrate-->>wsproj: ProjectEnvelope (migrated)
wsproj->>validate: validate(&migrated.project)
wsproj-->>User: ExitCode::SUCCESS
Loading

File-Level Changes

Change Details Files
New independent Rust workspace and worldscript-project crate for renderer-neutral project lifecycle.
  • Adds repo-root crates/Cargo.toml workspace with worldscript-project member and lockfile.
  • Implements schema.rs with serde-based structs mirroring key TS project types, plus constructor for StoryProject.
  • Defines envelope.rs with ProjectEnvelope, schema version constant, and structured JSON parse errors.
  • Adds migrate.rs with minimal migration framework and v1→v2 migration that backfills revision_note.
  • Adds validate.rs with structural validation enforcing unique IDs across characters, worlds, and manuscript sections.
  • Adds io.rs for plain JSON load/save with structured IO error types.
  • Exports crate API surface via lib.rs and adds wsproj binary CLI in src/bin/wsproj.rs.
  • Introduces lifecycle and fixture tests under crates/worldscript-project/tests to prove round-trip, migration, and validation behavior.
crates/Cargo.toml
crates/Cargo.lock
crates/worldscript-project/Cargo.toml
crates/worldscript-project/src/lib.rs
crates/worldscript-project/src/schema.rs
crates/worldscript-project/src/envelope.rs
crates/worldscript-project/src/migrate.rs
crates/worldscript-project/src/validate.rs
crates/worldscript-project/src/io.rs
crates/worldscript-project/src/bin/wsproj.rs
crates/worldscript-project/tests/lifecycle_test.rs
crates/worldscript-project/tests/fixtures_test.rs
Golden-master fixture parity between TS/Zod and Rust schema/validation.
  • Adds shared JSON fixtures covering empty, typical, large, missing-title, and truncated project shapes.
  • Creates Vitest suite projectGoldenMasters.test.ts to freeze current Zod-based import behavior on fixtures.
  • Rust tests deserialize fixtures into StoryProject to assert accept/reject parity and key counts.
tests/fixtures/project-golden-masters/empty-project.json
tests/fixtures/project-golden-masters/typical-project.json
tests/fixtures/project-golden-masters/large-project.json
tests/fixtures/project-golden-masters/missing-title.json
tests/fixtures/project-golden-masters/truncated.json
tests/unit/projectGoldenMasters.test.ts
crates/worldscript-project/tests/fixtures_test.rs
CI workflow extended with path-scoped Rust core job and updated changes filter/aggregator.
  • Extends changes job to detect crates/ modifications and emit changes.outputs.crates.
  • Adds core-rust job that runs fmt, check, clippy, and tests in crates workspace with Rust cache.
  • Updates ci-success aggregator to depend on core-rust and treat skipped status as pass, mirroring rust-tauri.
.github/workflows/ci.yml
Roadmap and migration ledger documentation updated for Wave 2 first slice and capability ownership.
  • Updates Wave 2 status and checklist in ROADMAP-QT-GPUI-DESKTOP.md to mark project headless API as in progress and detail completed actions.
  • Adds explicit note that Wave 2 exit criterion is met via headless tests/CLI, while storage, diagnostics, and AI remain deferred.
  • Introduces CORE-MIGRATION-LEDGER.md describing capabilities, ownership, migration priorities, and explicit non-goals for Wave 2.
docs/native/ROADMAP-QT-GPUI-DESKTOP.md
docs/native/CORE-MIGRATION-LEDGER.md
Tooling configuration and ignore rules adjusted for new crates workspace and intentionally invalid fixtures.
  • Adds crates/target/ to .gitignore to avoid tracking Rust build artifacts under the new workspace.
  • Updates biome.json to exclude crates/ and project-golden-masters fixtures to prevent lint errors on intentionally invalid JSON.
.gitignore
biome.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Aug 20, 2026

@amazon-q-developer amazon-q-developer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

This PR successfully introduces the first Wave 2 slice of Rust Core extraction with a well-designed headless harness. The implementation demonstrates solid architectural decisions and comprehensive testing.

Critical Issue (Must Fix)

Variable shadowing in validation logic - The validate.rs file reuses the variable name seen for three different HashSets, causing the latter declarations to shadow the former. This prevents proper validation of character and world IDs, as only the manuscript section IDs are effectively checked.

Strengths

  • Clean separation of concerns across modules (schema, validation, migration, I/O, envelope)
  • Comprehensive test coverage with 9 tests covering full lifecycle, corruption handling, and validation
  • Excellent documentation and rationale in module comments
  • Golden-master fixtures for cross-language validation parity
  • Proper CI integration with path-scoped jobs and skip-is-pass logic
  • Zero GUI dependencies proven via headless test execution

Architecture Review

The module structure is well thought out. The migration system is extensible, error handling is robust with structured error types, and the envelope versioning pattern provides a solid foundation for future schema evolution.

Once the critical validation shadowing issue is resolved, this PR will be ready to merge.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

Comment thread crates/worldscript-project/src/validate.rs Outdated
@codeant-ai

codeant-ai Bot commented Aug 20, 2026

Copy link
Copy Markdown

🏁 CodeAnt Quality Gate Results

Commit: f728850b
Scan Time: 2026-08-20 07:29:00 UTC

✅ Overall Status: PASSED

Quality Gate Details

Quality Gate Status Details
Secrets ✅ PASSED 0 secrets found
Duplicate Code ✅ PASSED 0.0% duplicated
SAST ✅ PASSED No security issues
Bugs ✅ PASSED Rating S: 3 bugs
IAC ✅ PASSED Rating S: No issues

View Full Results

Comment thread crates/worldscript-project/src/envelope.rs
…niqueness

Correctness note: the shadowing itself never caused a bug - each
HashSet::new() rebinding is a genuinely fresh, independent set, so all
three record types (characters/worlds/sections) were already checked
correctly. Renamed to seen_characters/seen_worlds/seen_sections purely
for readability (avoids exactly the kind of reviewer confusion this
caused), and clarified the doc comment + added a test proving the
actual intended design: uniqueness is per-record-type, not global -
a character and a section may share an id.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread crates/worldscript-project/src/migrate.rs
Comment thread crates/worldscript-project/src/schema.rs
@qnbs

qnbs commented Aug 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04526a0d27

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yml
Comment thread tests/unit/projectGoldenMasters.test.ts Outdated
Comment thread crates/worldscript-project/src/migrate.rs
Comment thread crates/worldscript-project/src/schema.rs
Comment thread crates/worldscript-project/src/schema.rs Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread crates/Cargo.toml
…l field mismatches

Three CodeAnt findings, all verified valid:

- migrate_to_latest's while loop only runs when schema_version <
  CURRENT_SCHEMA_VERSION, so a NEWER version silently passed through
  unchanged - if later re-saved, any fields this crate doesn't know
  about are dropped (serde ignores unknown fields on deserialize).
  Added an explicit upfront check rejecting schema_version >
  CURRENT_SCHEMA_VERSION with a new MigrationError::FutureVersion
  variant (renamed the error enum from the single-purpose
  UnknownSchemaVersionError to MigrationError to hold both cases).

- StorySection.content was a required field, but
  services/projectImportSchema.ts's storySectionSchema has
  `content: z.string().optional().default('')` - valid TS project
  files with sections omitting content would be rejected here. Added
  #[serde(default)].

- Found the same class of bug myself while re-auditing after the
  above: World.description has the identical optional-with-default
  pattern in Zod (unlike WorldLocation.description, which really is
  required) but was missing #[serde(default)] here too. Fixed.

Added 3 new tests covering all three fixes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
crates/worldscript-project/src/io.rs (1)

32-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Implement Error::source() for IoError.

The variants wrap concrete causes. source() currently returns None, so error-chain reporters lose the underlying std::io::Error and serde_json::Error. Display inlines the cause text, so this only affects structured reporting.

♻️ Proposed refactor
-impl std::error::Error for IoError {}
+impl std::error::Error for IoError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            IoError::Read(e) | IoError::Write(e) => Some(e),
+            IoError::Serialize(e) => Some(e),
+            IoError::Parse(e) => Some(e),
+        }
+    }
+}

ParseError must implement std::error::Error for the Parse arm.

🤖 Prompt for AI Agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

In `@crates/worldscript-project/src/io.rs` at line 32, Implement
std::error::Error::source for IoError, returning the wrapped std::io::Error for
its I/O variant and the wrapped serde_json::Error for its JSON variant; also
ensure ParseError implements std::error::Error so the Parse variant can expose
its underlying cause. Preserve the existing Display behavior.
crates/worldscript-project/src/migrate.rs (1)

27-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Derive the target version from source_version.

apply hardcodes 2. The trait documents the step as source_version + 1. Deriving the value keeps the step consistent if the registry order or the version numbering changes.

♻️ Proposed refactor
-        envelope.schema_version = 2;
+        envelope.schema_version = self.source_version() + 1;
🤖 Prompt for AI Agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

In `@crates/worldscript-project/src/migrate.rs` around lines 27 - 33, Update
MigrateV1ToV2::apply to set envelope.schema_version from the migration step’s
source_version plus one instead of hardcoding 2, while preserving the existing
revision_note behavior and returned envelope.
🤖 Prompt for all review comments with AI agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

Inline comments:
In `@crates/worldscript-project/src/bin/wsproj.rs`:
- Around line 41-53: Update the demo-lifecycle flow around
ProjectEnvelope::current, save_project, and migrate_to_latest to construct and
save a version 1 envelope instead of the current version 2 envelope. After
loading, assert migration produces schema version 2 and the expected migrated
revision_note, while preserving the existing round-trip and validation checks.

In `@crates/worldscript-project/src/migrate.rs`:
- Around line 63-71: Update the migration loop in migrate_to_latest to record
the envelope schema_version before step.apply, then validate that the returned
envelope has advanced beyond the previous version; return an appropriate
migration error when it does not, preventing repeated application of the same
step.
- Around line 59-63: Update parse_envelope and migrate_to_latest to reject
ProjectEnvelope values whose schema_version exceeds CURRENT_SCHEMA_VERSION,
returning UnknownSchemaVersionError instead of leaving them unchanged. Add a
regression test covering schemaVersion: 3 and verify the unsupported version is
rejected.

In `@tests/fixtures/project-golden-masters/typical-project.json`:
- Around line 62-63: Update the wordCount value for sec-2 to 9, matching the
nine words in its content and the established fixture data.

In `@tests/unit/projectGoldenMasters.test.ts`:
- Around line 7-8: Shorten the explanations for both QNBS-v3 comments so each
complete comment, including its rationale, fits on one physical line; preserve
the existing guidance about using path.join instead of new URL and the Vite
asset-URL issue.

---

Nitpick comments:
In `@crates/worldscript-project/src/io.rs`:
- Line 32: Implement std::error::Error::source for IoError, returning the
wrapped std::io::Error for its I/O variant and the wrapped serde_json::Error for
its JSON variant; also ensure ParseError implements std::error::Error so the
Parse variant can expose its underlying cause. Preserve the existing Display
behavior.

In `@crates/worldscript-project/src/migrate.rs`:
- Around line 27-33: Update MigrateV1ToV2::apply to set envelope.schema_version
from the migration step’s source_version plus one instead of hardcoding 2, while
preserving the existing revision_note behavior and returned envelope.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 934e337a-483f-43a9-b32f-a669e58cb941

📥 Commits

Reviewing files that changed from the base of the PR and between 73d79d4 and ae037a0.

⛔ Files ignored due to path filters (1)
  • crates/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • .github/workflows/ci.yml
  • .gitignore
  • biome.json
  • crates/Cargo.toml
  • crates/worldscript-project/Cargo.toml
  • crates/worldscript-project/src/bin/wsproj.rs
  • crates/worldscript-project/src/envelope.rs
  • crates/worldscript-project/src/io.rs
  • crates/worldscript-project/src/lib.rs
  • crates/worldscript-project/src/migrate.rs
  • crates/worldscript-project/src/schema.rs
  • crates/worldscript-project/src/validate.rs
  • crates/worldscript-project/tests/fixtures_test.rs
  • crates/worldscript-project/tests/lifecycle_test.rs
  • docs/native/CORE-MIGRATION-LEDGER.md
  • docs/native/ROADMAP-QT-GPUI-DESKTOP.md
  • tests/fixtures/project-golden-masters/empty-project.json
  • tests/fixtures/project-golden-masters/large-project.json
  • tests/fixtures/project-golden-masters/missing-title.json
  • tests/fixtures/project-golden-masters/truncated.json
  • tests/fixtures/project-golden-masters/typical-project.json
  • tests/unit/projectGoldenMasters.test.ts

Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Comment thread crates/worldscript-project/src/bin/wsproj.rs Outdated
Comment thread crates/worldscript-project/src/migrate.rs Outdated
Comment thread crates/worldscript-project/src/migrate.rs
Comment thread tests/fixtures/project-golden-masters/typical-project.json Outdated
Comment thread tests/unit/projectGoldenMasters.test.ts Outdated
@qnbs

qnbs commented Aug 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0eed529534

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yml Outdated
Comment thread crates/worldscript-project/src/schema.rs
Comment thread crates/worldscript-project/src/schema.rs
Comment thread crates/worldscript-project/tests/fixtures_test.rs
Comment thread crates/worldscript-project/src/bin/wsproj.rs Outdated
Comment thread crates/worldscript-project/src/bin/wsproj.rs Outdated
- WorldLocation now models type (required enum), coordinates, and
  population — matching services/projectImportSchema.ts's
  worldLocationSchema exactly, instead of silently dropping them on
  save (data loss risk for the type field that TS requires).
- StorySection.status is now a closed SectionStatus enum
  (draft/outline/first-draft/revised/final) instead of Option<String>,
  matching the Zod enum instead of accepting unsupported values.
- Add a round-trip fixture test proving location fields survive
  deserialize -> serialize -> reparse.
- OSV scan now also covers crates/Cargo.lock (was only scanning
  pnpm-lock.yaml + src-tauri/Cargo.lock).
- changes job's path filter now also flags core-rust for changes
  under tests/fixtures/project-golden-masters/, since fixtures_test.rs
  reads them directly.
- Add a Cargo dependabot entry for /crates (previously only src-tauri
  was covered).
- Fix two QNBS-v3 comments wrapped across two physical lines (hard
  rule violation) in tests/unit/projectGoldenMasters.test.ts and one
  introduced by this PR's own ci.yml core-rust job comment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@qnbs

qnbs commented Aug 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@qnbs

qnbs commented Aug 20, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

The rule was already documented as a hard rule, but got violated again
this session (twice, one of them self-introduced in the same PR that
was fixing a prior violation) because the rule described the outcome
without a concrete verification step. Add a mandatory grep-based
self-check to run before any commit touching a QNBS-v3 comment,
per user instruction to codify this so it stops requiring repeated
bot-triggered correction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… PR 409

- migrate_to_latest now guards against a non-advancing migration step
  looping forever (new MigrationError::NonAdvancing), instead of
  relying purely on the Migration trait's unenforced +1 contract.
- typical-project.json's sec-2 wordCount corrected from 8 to the
  actual 9-word count.
- wsproj demo-lifecycle now exercises a real v1 -> v2 migration: hand-
  authors a v1 envelope, saves and reloads it from disk, migrates it,
  and asserts the backfilled revision_note - the previous version only
  ever migrated an already-current v2 envelope (a no-op) while still
  printing "migrated successfully".
- wsproj's demo scratch files now use an unpredictable filename plus
  create_new (O_EXCL) semantics instead of a PID-only predictable path
  written via fs::write, which would have followed a pre-planted
  symlink and truncated its target on a shared Unix system.
- StorySection now models prompt/color/position/characterIds/worldIds/
  act/sceneStart/sceneDuration/sceneLocationId/povCharacterId, closing
  a silent-data-loss gap where a Rust load/save round-trip dropped all
  of this scene metadata for any current-schema project that used it.
  word_count/act divergences from Zod's unrestricted z.number() are
  now documented as intentional Rust-side tightening, following the
  existing precedent in validate.rs's ID-uniqueness comment.
- fixtures_test.rs's three "is_accepted" tests now also call validate()
  after successful deserialization, so the golden-master parity claim
  covers the full accept pipeline, not just structural deserialization.
- Removed four QNBS-v3 inline comments this PR had added/edited in
  ci.yml and dependabot.yml - both AGENTS.md and CLAUDE.md already say
  YAML/JSON config gets no inline QNBS-v3 comments, rationale belongs
  in the commit message (this message).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@qnbs

qnbs commented Aug 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@qnbs
qnbs merged commit d00286f into main Aug 20, 2026
34 checks passed
@qnbs
qnbs deleted the feat/wave2-worldscript-project-crate branch August 20, 2026 07:50
qnbs added a commit that referenced this pull request Aug 20, 2026
CodeAnt correctly flagged that a real Redux-persisted project (using
EntityState normalization for characters/worlds) would fail parse_envelope
today. This is deliberate, existing scope from PR #409's schema.rs -
not a regression introduced here - but that context lived only in
schema.rs, not in this command's own docs. Add a pointer so a future
reader of project_core.rs alone sees the limitation without having to
already know schema.rs's history.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
qnbs added a commit that referenced this pull request Aug 20, 2026
…R B) (#426)

* feat(core): wire worldscript_project_validate Tauri command (Wave 2 PR B)

Strangler proof point per docs/native/CORE-MIGRATION-LEDGER.md's Wave
2 plan: a new src-tauri/src/commands/project_core.rs exposes
worldscript_project_validate, delegating to the renderer-neutral
worldscript-project crate (parse -> migrate to current schema ->
validate) instead of any Tauri-local logic.

worldscript-project is added as a path dependency in src-tauri's
Cargo.toml, referencing a crate that is itself a member of the
separate crates/ Cargo workspace - confirmed this cross-workspace
path dependency compiles and links cleanly (cargo check/test/clippy
all pass) without requiring the two workspaces to be unified, keeping
the Wave 2 PR 1 decision to keep them independent intact.

Backend-only: no frontend call site, no changes to
services/desktopPlatform.ts or services/fs/projectFsStore.ts /
services/storageService.ts's dispatch. This only proves the Tauri <->
Rust Core command boundary compiles and runs correctly; wiring an
actual frontend caller is separate, later work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(core): note the EntityState normalization gap in project_core.rs

CodeAnt correctly flagged that a real Redux-persisted project (using
EntityState normalization for characters/worlds) would fail parse_envelope
today. This is deliberate, existing scope from PR #409's schema.rs -
not a regression introduced here - but that context lived only in
schema.rs, not in this command's own docs. Add a pointer so a future
reader of project_core.rs alone sees the limitation without having to
already know schema.rs's history.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant