Skip to content

refactor: migrate selected runtime schemas to Effect Schema#268

Closed
Astro-Han wants to merge 3 commits into
claude/upstream-sync-209-pr2-movesfrom
claude/upstream-sync-209-pr3-effect-schema
Closed

refactor: migrate selected runtime schemas to Effect Schema#268
Astro-Han wants to merge 3 commits into
claude/upstream-sync-209-pr2-movesfrom
claude/upstream-sync-209-pr3-effect-schema

Conversation

@Astro-Han

Copy link
Copy Markdown
Owner

Summary

Squashes upstream's Effect Schema migration batch (16 PRs, dated Apr 21–24 2026) into one PawWork commit. Selectively adopts the schema-definition-layer changes while preserving PawWork's namespace-API and Zod-typed BusEvent layers where divergence is too deep.

Upstream PRs included: #23716, #23740, #23744, #23745, #23747, #23749, #23752, #23754, #23756, #23757, #23763, #24005, #24040, #24169, #24213

Why

Stage D of the foundation sync (#209). The schema-definition layer (Config.Info, ConfigPermission.Info, ConfigAgent.Info, several */schema.ts files, util/effect-zod walker) is core runtime work — this PR adopts those. Per @yuhan: "Effect Schema is core runtime work."

The consumer layer (session, bus, provider, snapshot, permission, mcp namespaces) has too much PawWork divergence to take upstream's redesign wholesale. Those stay on PawWork's existing Zod / namespace API; the schema layer changes still flow through via the .zod accessor pattern.

What landed (24 files)

  • Config / Permission / Agent schemas migrated to Effect Schema canonical form. PawWork callers use Config.Info.zod (server/instance/{config,global}.ts, script/schema.ts).
  • Schema-only files migrated in control-plane, permission, project, pty, question, sync, tool/schema.ts, session/schema.ts, tool/edit.ts, tool/todo.ts.
  • util/effect-zod.ts walker enhanced to derive .zod from Effect Schema at runtime, plus walker tests.
  • packages/sdk/js/src/v2/gen/types.gen.ts regenerated to reflect schema shape changes (Stage I would've done this anyway).
  • Test fixtures updated (config.test.ts, permission/next.test.ts, compaction.test.ts, session.test.ts, effect-zod.test.ts).

What was preserved (PawWork divergence)

  • session/{session,message-v2,prompt,export,message,revert,summary,todo,status,compaction,projectors}.ts — PawWork's session domain stays Zod-shaped. MessageV2's FileSource/SymbolSource/ResourceSource carry PawWork-only attachment metadata that upstream's Effect Schema variants drop.
  • bus/bus-event.ts — PawWork keeps Zod-typed BusEvent.define. ~30 PawWork tests + divergent consumers (server/instance/*, acp/agent.ts, file/watcher.ts) read evt.properties as inferred type, not unknown.
  • {snapshot,permission,mcp,provider}/index.ts — PawWork uses a "namespace + XValue alias" pattern that upstream redesigned to flat exports. Keeping HEAD preserves Snapshot.track, Permission.ask, Mcp.add, Provider.list.
  • provider/{provider,auth,models}.ts — PawWork's volcengine/zen integration carries divergent code paths (VOLCENGINE_PLAN_* constants, HTTP-Referer/X-Title carve-out per project_rename_blockers.md).
  • {file,project,pty,sync,ide,lsp/client,command,control-plane/workspace,worktree,question,util/schema}/{index,*}.ts — kept PawWork API surface for callers.

Skipped commit: 93940a1859 (provider domain Effect Schema migration) — entire diff sat on PawWork carve-out files; reapplied through PawWork-local provider when divergence settles.

Related Issue

#209

How To Verify

bun install
bun run --cwd packages/core typecheck
bun run --cwd packages/opencode typecheck
bun run --cwd packages/util typecheck
bun run --cwd packages/ui typecheck
bun run --cwd packages/desktop-electron typecheck

All 5 packages typecheck clean.

Stacked on

Base is claude/upstream-sync-209-pr2-moves (#266). Will auto-rebase to dev after #265#266 chain merges.

Checklist

  • I linked the related issue ([Feature] Track selective upstream backports from opencode v1.14.17-v1.14.22 #209)
  • This PR has type, scope, and priority labels (upstream / harness / P3)
  • I listed the relevant verification steps
  • No visible UI changes — N/A
  • No desktop/packaging/updater impact — N/A (runtime schema only)
  • I considered docs/dependencies — packages/sdk/js/v2/gen/types.gen.ts regenerated; no new deps
  • Targeting dev (via stacked PR), Conventional Commits English title

Pure mechanical rename of the workspace package. packages/shared is
moved to packages/core; all consumers update imports from
@opencode-ai/shared/* to @opencode-ai/core/*. No file content changes
beyond the package rename.

PawWork-local consumers (packages/util, packages/ui, packages/opencode,
packages/desktop-electron runtime-import-guard test) updated.

This is the first half of upstream's "shared → core" refactor; the
follow-up commits that move modules (Global, log, flag, cross-spawn,
npm) into core land in a separate PR (#209 PR2).

Refs: #209
Pulls upstream PR follow-ups to the shared→core rename:
- 1a734adb4d core: consolidate shared infrastructure into core package
- 705f792e87 core: move Global module to @opencode-ai/core
- 3eee2f6afa core: move cross-spawn-spawner from opencode to core
- 1e98167b0e core: move cross-spawn-spawner to root and remove unused types
- f5dce6d960 core: move npm service to core package

Also pulls the npm-config snapshot from upstream HEAD (Stage C of #209
intake plan): packages/core/src/npm.ts, npm-config.ts, npm-config.test.ts.
The pre-existing packages/opencode/test/npm.test.ts is removed.

PawWork carve-outs:
- packages/core/src/global.ts uses Runtime.appName() instead of
  hardcoded "opencode" so the pawwork-namespace data dir is preserved.
- packages/opencode/src/global/index.ts is kept as PawWork's local
  Runtime-aware Global module; upstream's auto-rewritten
  @opencode-ai/core/global imports flow through to the carve-out.
- packages/core/src/effect/logger.ts uses PawWork's namespace-style Log
  API (Log.create / Log.Default / Log.init) rather than upstream HEAD's
  flat-export style. PawWork callers expect the namespace shape.

Mechanical cleanup:
- packages/opencode/src/installation/meta.ts is removed; callers use
  @opencode-ai/core/installation/version (InstallationVersion /
  InstallationChannel) directly.
- All ../util/log, ../flag/flag, @/effect/* and similar local imports
  rewritten to @opencode-ai/core/* equivalents (~120 files).
- @effect/opentelemetry catalog entry added to root package.json
  (4.0.0-beta.46, matching the rest of the effect ecosystem).

Verified: typecheck clean across packages/{core, opencode, util, ui,
desktop-electron}.

Refs: #209
Squashes upstream PRs #23716, #23740, #23744, #23745, #23747, #23749,
#23752, #23754, #23756, #23757, #23763, #24005, #24040, #24169, #24213
into a single PawWork commit. Ranges over 16 upstream commits in
date order from upstream's Effect Schema migration batch.

What landed:
- Config.Info, ConfigPermission.Info, ConfigAgent.Info schema definitions
  migrated to Effect Schema canonical form. PawWork callers use
  Config.Info.zod accessor where Hono validators or Zod-style decoders
  are still needed.
- Schema definition files in control-plane, permission, project, pty,
  question, sync, tool, session migrated to Effect Schema.
- packages/opencode/src/util/effect-zod.ts walker enhanced to derive
  .zod from Effect Schema at runtime, plus tests.
- packages/sdk/js/v2/gen/types.gen.ts regenerated to reflect schema
  shape changes.

What was preserved (PawWork divergence kept on Zod / namespace API):
- packages/opencode/src/session/{session,message-v2,prompt,export,message,revert,summary,todo,status,compaction,projectors}.ts
  — PawWork's session domain stays Zod-shaped to keep MessageV2
  PawWork-only types (FileSource/SymbolSource/ResourceSource carry
  PawWork attachment metadata) compatible with current callers.
- packages/opencode/src/bus/bus-event.ts — PawWork keeps Zod-typed
  BusEvent.define so the 30+ PawWork test fixtures and divergent
  consumers (server/instance/*, acp/agent.ts, file/watcher.ts) keep
  reading evt.properties as their schema's inferred type rather than
  unknown.
- packages/opencode/src/{snapshot,permission,mcp,provider}/index.ts —
  these modules use a PawWork "namespace + XValue alias" pattern that
  upstream redesigned. Keeping HEAD here preserves Snapshot.track,
  Permission.ask, Mcp.add, Provider.list etc. for PawWork callers.
- packages/opencode/src/provider/* — PawWork's volcengine/zen
  integration carries divergent code paths (VOLCENGINE_PLAN constants,
  HTTP-Referer/X-Title carve-out per project_rename_blockers.md).
- packages/opencode/src/{file,project,pty,sync,ide,lsp/client,command,
  control-plane/workspace,worktree,question,util/schema}/{index,*}.ts
  — kept PawWork API surface for callers.

Skipped commits in this range (no PawWork-applicable change after
carve-outs): 93940a1859 (provider domain) — provider.ts is a PawWork
permanent carve-out; the migration is reapplied to PawWork's local
provider only when divergence settles.

Verified: typecheck clean across packages/{core, opencode, util, ui,
desktop-electron}.

Refs: #209
@Astro-Han Astro-Han added P3 Low priority upstream Tracked upstream or vendor behavior harness Model harness, prompts, tool descriptions, and session mechanics labels Apr 27, 2026
@coderabbitai

coderabbitai Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 34aab46b-1c7e-4b90-86e9-39c142d67c9b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/upstream-sync-209-pr3-effect-schema

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

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request migrates configuration and identifier schemas to use Effect Schema as the source of truth, deriving Zod schemas for compatibility. It removes the ZodPreprocess utility and the __originalKeys hack in favor of native Effect transformations. Feedback was provided regarding the isZodType utility, which incorrectly checks for a non-standard _zod property instead of using instanceof z.ZodType.

Comment on lines +48 to +50
function isZodType(value: unknown): value is z.ZodTypeAny {
return typeof value === "object" && value !== null && "_zod" in value
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The isZodType guard checks for a _zod property, which is not a standard property on Zod type instances (they typically use _def internally). This will cause zodObject to always fall back to walk(schema.ast), bypassing any hand-crafted or refined Zod schemas attached via .zod statics (such as the .strict() and .meta() calls in config.ts). Using instanceof z.ZodType is the standard approach and ensures compatibility with Zod v4 patterns, where refinements are common.

Suggested change
function isZodType(value: unknown): value is z.ZodTypeAny {
return typeof value === "object" && value !== null && "_zod" in value
}
function isZodType(value: unknown): value is z.ZodTypeAny {
return value instanceof z.ZodType
}
References
  1. In Zod v4, it is a valid pattern to call .omit() on a schema after applying .refine(). This strips the refinement and returns a ZodObject.
  2. Adhere to established codebase conventions for error handling (e.g., using instanceof Error for same-process errors) to maintain consistency, rather than introducing new patterns like type guards.

@Astro-Han Astro-Han force-pushed the claude/upstream-sync-209-pr2-moves branch 3 times, most recently from 6f1633f to 5e335cb Compare April 27, 2026 18:02
@Astro-Han Astro-Han deleted the branch claude/upstream-sync-209-pr2-moves April 27, 2026 18:29
@Astro-Han Astro-Han closed this Apr 27, 2026
@Astro-Han

Copy link
Copy Markdown
Owner Author

Superseded by #280 (rebased onto current dev — actual change is 24 files, the 225 here was inflated by PR1+PR2 merge-commit SHA mismatch).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

harness Model harness, prompts, tool descriptions, and session mechanics P3 Low priority upstream Tracked upstream or vendor behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant