Skip to content

Selective Path Coercion (100% Public API Coercion implementation)#576

Closed
yamcodes wants to merge 38 commits into
coercionfrom
coercion-less-internars
Closed

Selective Path Coercion (100% Public API Coercion implementation)#576
yamcodes wants to merge 38 commits into
coercionfrom
coercion-less-internars

Conversation

@yamcodes

@yamcodes yamcodes commented Dec 22, 2025

Copy link
Copy Markdown
Owner

This is an attempt to implement coercion, this time by relying on 100% public API which makes ArkEnv much, much more reliable (100% reliable) instead of having to compromise on reliability.

Closes #577

Summary by CodeRabbit

Release Notes

  • Breaking Changes

    • Removed parsedNumber and parsedBoolean keywords.
    • boolean keyword removed; numeric and boolean coercion now centralized across the package.
  • Refactor

    • Coercion mechanism refactored to use stable public APIs instead of internal implementation mechanisms.
  • Documentation

    • Added comprehensive design and specification documentation for the refactored coercion pipeline.

✏️ Tip: You can customize this high-level summary in your review settings.

yamcodes and others added 30 commits December 21, 2025 02:49
…chema definitions and refinements, and refine various type and regex functionalities.
…ort` to use `parsedNumber`, and integrate `port` into the ArkType scope.
…, and enhance `number` and `boolean` coercion in `arkenv`.
…ransformation, supporting numeric refinements.
…and boolean type coercion and add new playground debug files.
…oerce` utility and remove playground files.
…t coercion from their definitions and from the `type` export, relying on global coercion instead.
…bers, booleans, ranges, and optional properties.
…oolean nodes, improving internal handling and type inference
… boolean types, ensuring correct application order and type handling
…numeric and boolean types, adding warnings for reliance on undocumented ArkType APIs
…e type assertions in the `coerce` function.
@changeset-bot

changeset-bot Bot commented Dec 22, 2025

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 21146bd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes changesets to release 6 packages
Name Type
arkenv Patch
@repo/keywords Minor
@repo/scope Minor
@arkenv/bun-plugin Patch
@arkenv/vite-plugin Patch
@repo/types Major

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel

vercel Bot commented Dec 22, 2025

Copy link
Copy Markdown

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

Project Deployment Review Updated (UTC)
arkenv Ready Ready Preview, Comment Dec 22, 2025 1:46pm

@coderabbitai

coderabbitai Bot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This PR refactors arkenv's coercion mechanism from relying on internal ArkType APIs to using public APIs. It replaces internal schema mutation with a pipeline-based approach that introspects schemas via .in.json, identifies numeric and boolean coercion paths, and applies transformations through .pipe() before validation.

Changes

Cohort / File(s) Summary
Coercion Implementation Refactor
packages/arkenv/src/utils/coerce.ts
Replaced internal API-based coercion with public API approach. Added findCoercionPaths, applyCoercion, isNumeric, and isBoolean utilities. Updated coerce function signature from coerce(schema: any): any to coerce<t, $ = {}>(schema: BaseType<t, $>): BaseType<t, $>. Now uses schema introspection via .in.json and pipeline composition.
Keywords Module
packages/internal/keywords/src/index.ts
Removed exported constants parsedNumber and parsedBoolean. Retained loose coercion morphs (maybeParsedNumber, maybeParsedBoolean) and kept port and host definitions.
Configuration Updates
packages/arkenv/package.json, packages/arkenv/ARKTYPE_INTERNALS.md
Added @ark/schema (v0.56.0) as dev dependency. Updated internal API documentation to reflect removal of internal property usage and migration to public .in.json and .pipe() APIs.
Playground Example
apps/playgrounds/node/index.ts
Refactored to use separate type-based schema via type({...}) assigned to Env. Added RANGEPORT field. Updated arkenv invocation to arkenv(Env). Added debugging output via Env.toJsonSchema() and Env.toJSON().
Changesets
.changeset/cyan-loops-hear.md, .changeset/few-rabbits-battle.md, .changeset/humble-lizards-judge.md, .changeset/open-spiders-tan.md
Multiple changelog entries documenting the transition to Selective Path Coercion, removal of parsedNumber changelog, simplification of keywords, and alignment with central coercion strategy.
Design Documentation
openspec/changes/coercion-public-api/design.md, openspec/changes/coercion-public-api/proposal.md, openspec/changes/coercion-public-api/spec.md, openspec/changes/coercion-public-api/tasks.md
Added comprehensive design documentation covering the Pipeline Wrapper Pattern, rationale for refactor, coercion refactor specification, and completed implementation phases (Research & Scaffolding, Implementation, Validation).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Primary focus: packages/arkenv/src/utils/coerce.ts — Logic density is moderate with new utility functions (findCoercionPaths, applyCoercion), predicate helpers, and refactored control flow replacing internal API calls with public API introspection.
  • Key areas requiring attention:
    • Correctness of findCoercionPaths recursive traversal logic and path-detection rules for numeric/boolean types, unions, properties, and sequences
    • Validity of isNumeric and isBoolean node-detection predicates against ArkType schema structures
    • Pipeline composition in the updated coerce function signature and its interaction with .in.json introspection
    • Verification that removed internal API dependencies (.internal, .transform, internal node types) are not regressed

Possibly related PRs

Suggested labels

tests

Poem

🐰 A rabbit hops through coercion's rebirth,
No more secret tunnels through ArkType's earth!
With .in.json light and .pipe() so clean,
The purest public paths we've ever seen.
Selective and steady, the data flows right,
From strings into numbers—what a beautiful sight! ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR fully implements Issue #577 requirements: uses public ArkType introspection (.in.json) for selective path-based coercion, removes internal API dependencies, applies coercion non-destructively via pipeline pattern, and achieves the high-performance goal through single-pass introspection.
Out of Scope Changes check ✅ Passed All changes directly support the coercion refactor objective: documentation updates clarify the new approach, changesets document breaking changes and keyword simplifications, code refactors remove internal API usage, and playground updates demonstrate the public API usage.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title accurately describes the main change: implementation of selective path coercion using 100% public ArkType APIs, which is the central objective of the PR and evident across all modified files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch coercion-less-internars

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added the arkenv Changes to the `arkenv` npm package. label Dec 22, 2025
…rcion to public APIs via `type.pipe` and `schema.in.json`.
@github-actions github-actions Bot added the docs Adds or changes documentation, or acts as documentation in and of itself label Dec 22, 2025
…d introduce a PoC for generic path-based coercion.
…schema introspection and data-level coercion, removing reliance on internal APIs and updating documentation.
@yamcodes yamcodes changed the title Coercion (100% Public API implementation) Selective Path Coercion (100% Public API implementation) Dec 22, 2025
…arsing keywords and internal ArkType API usage, and simplifying the `port` keyword.
…amples workflow

- Removed the `id-token: write` permission from the `sync-examples.yml` workflow to streamline permissions and enhance security.
…th improved type annotations, null checks, and compatibility fixes.
@yamcodes
yamcodes marked this pull request as ready for review December 22, 2025 14:02
@yamcodes

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Dec 22, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
openspec/changes/coercion-public-api/proposal.md (1)

1-32: Proposal structure doesn't match required format.

Per coding guidelines, proposals should include sections: Why, What Changes (with BREAKING markers), and Impact. Currently the document has:

  • "Problem" → should be renamed to "Why"
  • "Solution" → should be restructured as "What Changes" with explicit BREAKING markers if applicable
  • "Impact" ✓ (correctly named)
  • "Implementation Rules" → optional, but good to have

Consider restructuring to match the expected format. As per coding guidelines for openspec/changes/*/proposal.md.

packages/arkenv/src/utils/coerce.ts (3)

9-11: Consider using type instead of interface.

Per coding guidelines, prefer type over interface for type definitions in TypeScript.

🔎 Proposed fix
-interface CoercionTarget {
-	path: string[];
-}
+type CoercionTarget = {
+	path: string[];
+};

119-136: Minor optimization opportunity: redundant nested object cloning.

When multiple targets share a common path prefix, the current implementation may re-clone the same intermediate objects multiple times (line 130 clones unconditionally). This is functionally correct but could be optimized by tracking already-cloned paths.

For typical env var schemas (flat structures), this is unlikely to be a performance concern.


16-31: Add JSDoc comment explaining which ArkType constructs produce each numeric pattern.

The logic correctly handles multiple representations of numeric types that ArkType generates. Consider documenting which patterns correspond to which ArkType constructs to aid future maintainers:

  • node === "number" → simple "number" type
  • domain === "number" → constrained numbers like "number >= 18" or "number % 2"
  • typeof n.unit === "number" → numeric literals like 1, 2, or "1 | 2"
  • n.kind === "intersection" && domain === "number" → intersection constraints
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1728e55 and 21146bd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • .changeset/cyan-loops-hear.md
  • .changeset/few-rabbits-battle.md
  • .changeset/humble-lizards-judge.md
  • .changeset/open-spiders-tan.md
  • apps/playgrounds/node/index.ts
  • openspec/changes/coercion-public-api/design.md
  • openspec/changes/coercion-public-api/proposal.md
  • openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md
  • openspec/changes/coercion-public-api/tasks.md
  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • packages/arkenv/src/utils/coerce.ts
  • packages/internal/keywords/src/index.ts
💤 Files with no reviewable changes (1)
  • .changeset/few-rabbits-battle.md
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{ts,tsx,json,md}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Biome for linting and formatting instead of ESLint and Prettier

Files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • openspec/changes/coercion-public-api/design.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md
  • openspec/changes/coercion-public-api/tasks.md
  • packages/internal/keywords/src/index.ts
  • apps/playgrounds/node/index.ts
packages/*/package.json

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Packages in packages/ directory must be published to npm and require changesets for versioning, proper exports, and type definitions

Files:

  • packages/arkenv/package.json
**/package.json

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Use workspace:* protocol for workspace dependencies between packages

Files:

  • packages/arkenv/package.json
{packages,apps,tooling}/**/package.json

📄 CodeRabbit inference engine (.cursor/rules/pnpm.mdc)

When referencing workspace packages in dependencies, use the workspace:* protocol instead of version numbers

Files:

  • packages/arkenv/package.json
openspec/changes/*/proposal.md

📄 CodeRabbit inference engine (openspec/AGENTS.md)

Create proposal.md with sections: Why, What Changes (with BREAKING markers), and Impact

Files:

  • openspec/changes/coercion-public-api/proposal.md
packages/arkenv/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/arktype.mdc)

packages/arkenv/**/*.ts: Use ArkType's type() function to define schemas in environment variable definitions
Leverage ArkType's type inference for TypeScript types instead of manual type definitions
Use the scoped $ type system for custom types defined in scope.ts
Keep environment variable schemas readable and TypeScript-like using ArkType syntax
Use union types for enums in ArkType schemas (e.g., "'dev' | 'prod'") instead of separate enum definitions
Leverage ArkType's built-in types (e.g., string.host, number.port) where possible in environment schemas
Convert ArkType validation errors to ArkEnvError for user-friendly error messages that include variable name and expected type

Files:

  • packages/arkenv/src/utils/coerce.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

**/*.{ts,tsx}: Prefer type over interface for type definitions in TypeScript
Use TypeScript 5.1+ features when appropriate
Leverage const type parameters for better inference in TypeScript
Use JSDoc comments for public APIs
Use tabs for indentation (configured in Biome)
Use double quotes for strings (configured in Biome)
Organize imports automatically (Biome handles this)
Avoid explicit types when TypeScript can infer them (noInferrableTypes error)
Use as const where appropriate for immutable values (useAsConstAssertion error)
Don't reassign function parameters (noParameterAssign error)
Place default parameters last in function signatures (useDefaultParameterLast error)
Always initialize enum values (useEnumInitializers error)
Declare one variable per statement (useSingleVarDeclarator error)
Avoid unnecessary template literals (noUnusedTemplateLiteral error)
Prefer Number.parseInt over global parseInt (useNumberNamespace error)
Use kebab-case for TypeScript filenames (e.g., create-env.ts)
Use camelCase for function names (e.g., createEnv)
Use PascalCase for type names (e.g., ArkEnvError)
Use UPPER_SNAKE_CASE for environment variables and constants
Include examples in JSDoc comments when helpful for public APIs
Document complex type logic with JSDoc comments
Use ArkEnvError for environment variable validation errors
Provide clear, actionable error messages that include the variable name and expected type

**/*.{ts,tsx}: Use createEnv(schema) as the main function for validated environment objects, available as the default export
Use built-in validators (host, port, url, email) from src/types.ts when available instead of custom validation
Use ArkEnvError for environment variable errors, not generic errors
Environment schema definitions should use built-in validators, ArkType string literals, and support default values in the schema pattern
Use logical grouping for related environment variables in schemas
Use descriptive env...

Files:

  • packages/arkenv/src/utils/coerce.ts
  • packages/internal/keywords/src/index.ts
  • apps/playgrounds/node/index.ts
packages/arkenv/src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Main library implementation should be in src/create-env.ts, built-in validators in src/types.ts, error handling in src/errors.ts, and utilities in src/utils.ts

Files:

  • packages/arkenv/src/utils/coerce.ts
openspec/changes/*/specs/**/spec.md

📄 CodeRabbit inference engine (openspec/AGENTS.md)

openspec/changes/*/specs/**/spec.md: Use ## ADDED|MODIFIED|REMOVED|RENAMED Requirements as delta headers in spec.md files under changes
Ensure change proposals contain delta specs for each affected capability under changes/[change-id]/specs/[capability]/spec.md

Files:

  • openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md
openspec/**/spec.md

📄 CodeRabbit inference engine (openspec/AGENTS.md)

openspec/**/spec.md: Include at least one scenario per requirement using #### Scenario: header format with WHEN and THEN bullet points
Use SHALL/MUST for normative requirements rather than should/may unless intentionally non-normative

Files:

  • openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md
openspec/changes/*/tasks.md

📄 CodeRabbit inference engine (openspec/AGENTS.md)

Create tasks.md with numbered implementation checklist items as checkboxes (- [ ] format)

Files:

  • openspec/changes/coercion-public-api/tasks.md
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/coding-guidelines.mdc)

Use barrel exports (index.ts) for package entry points

Files:

  • packages/internal/keywords/src/index.ts
  • apps/playgrounds/node/index.ts
🧠 Learnings (23)
📓 Common learnings
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Leverage ArkType's built-in types (e.g., `string.host`, `number.port`) where possible in environment schemas
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Keep environment variable schemas readable and TypeScript-like using ArkType syntax
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Use union types for enums in ArkType schemas (e.g., `"'dev' | 'prod'"`) instead of separate enum definitions
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: ArkType validates environment variables at runtime and TypeScript types are inferred from the schema definition
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Convert ArkType validation errors to `ArkEnvError` for user-friendly error messages that include variable name and expected type
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Use ArkType's `type()` function to define schemas in environment variable definitions
Learnt from: yamcodes
Repo: yamcodes/arkenv PR: 498
File: apps/playgrounds/node/index.ts:2-2
Timestamp: 2025-12-05T20:33:10.676Z
Learning: ArkType 2.1.28+ supports Standard Schema specification, allowing interoperability with other Standard Schema-compliant validation libraries (e.g., Zod, Valibot) within the same schema definition
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Leverage ArkType's type inference for TypeScript types instead of manual type definitions
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to **/*.{ts,tsx} : Environment schema definitions should use built-in validators, ArkType string literals, and support default values in the schema pattern
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Leverage ArkType's type inference for TypeScript types instead of manual type definitions

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Keep environment variable schemas readable and TypeScript-like using ArkType syntax

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • openspec/changes/coercion-public-api/design.md
  • .changeset/open-spiders-tan.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md
  • packages/internal/keywords/src/index.ts
  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Leverage ArkType's built-in types (e.g., `string.host`, `number.port`) where possible in environment schemas

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • openspec/changes/coercion-public-api/design.md
  • .changeset/open-spiders-tan.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md
  • packages/internal/keywords/src/index.ts
  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Use ArkType's `type()` function to define schemas in environment variable definitions

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • packages/internal/keywords/src/index.ts
  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Convert ArkType validation errors to `ArkEnvError` for user-friendly error messages that include variable name and expected type

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Use union types for enums in ArkType schemas (e.g., `"'dev' | 'prod'"`) instead of separate enum definitions

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • openspec/changes/coercion-public-api/design.md
  • .changeset/open-spiders-tan.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • packages/internal/keywords/src/index.ts
  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/scope.ts : Define custom types in `scope.ts` using ArkType's scoped type system for reusability across schemas

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • .changeset/open-spiders-tan.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to **/*.{ts,tsx} : Environment schema definitions should use built-in validators, ArkType string literals, and support default values in the schema pattern

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • .changeset/open-spiders-tan.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: ArkType validates environment variables at runtime and TypeScript types are inferred from the schema definition

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • packages/arkenv/src/utils/coerce.ts
  • apps/playgrounds/node/index.ts
📚 Learning: 2025-11-24T16:03:45.295Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Use the scoped `$` type system for custom types defined in `scope.ts`

Applied to files:

  • packages/arkenv/ARKTYPE_INTERNALS.md
  • packages/arkenv/package.json
  • .changeset/open-spiders-tan.md
  • openspec/changes/coercion-public-api/proposal.md
  • packages/arkenv/src/utils/coerce.ts
📚 Learning: 2025-09-10T19:35:18.179Z
Learnt from: yamcodes
Repo: yamcodes/arkenv PR: 136
File: .changeset/vast-bananas-win.md:2-3
Timestamp: 2025-09-10T19:35:18.179Z
Learning: The arkenv package is currently in v0.x.x (pre-1.0) development phase, where breaking changes are acceptable in minor version bumps according to semantic versioning conventions.

Applied to files:

  • packages/arkenv/package.json
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:04:11.901Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/monorepo.mdc:0-0
Timestamp: 2025-11-24T16:04:11.901Z
Learning: packages/arkenv should not depend on other workspace packages; packages/vite-plugin depends on arkenv; apps/www may depend on workspace packages

Applied to files:

  • packages/arkenv/package.json
📚 Learning: 2025-11-24T16:04:00.957Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-11-24T16:04:00.957Z
Learning: Applies to **/*.{ts,tsx} : Prefer `Number.parseInt` over global `parseInt` (`useNumberNamespace` error)

Applied to files:

  • .changeset/open-spiders-tan.md
  • packages/internal/keywords/src/index.ts
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: For breaking changes, always create an OpenSpec proposal first

Applied to files:

  • openspec/changes/coercion-public-api/proposal.md
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to packages/arkenv/src/**/*.ts : Main library implementation should be in `src/create-env.ts`, built-in validators in `src/types.ts`, error handling in `src/errors.ts`, and utilities in `src/utils.ts`

Applied to files:

  • openspec/changes/coercion-public-api/proposal.md
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: For architecture changes, review `openspec/project.md` for conventions

Applied to files:

  • openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to **/*.{ts,tsx} : Use built-in validators (host, port, url, email) from `src/types.ts` when available instead of custom validation

Applied to files:

  • packages/internal/keywords/src/index.ts
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to **/*.{ts,tsx} : Use `createEnv(schema)` as the main function for validated environment objects, available as the default export

Applied to files:

  • apps/playgrounds/node/index.ts
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to **/*.{ts,tsx} : Use `ArkEnvError` for environment variable errors, not generic errors

Applied to files:

  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-29T22:11:39.931Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to **/*.{ts,tsx} : Use logical grouping for related environment variables in schemas

Applied to files:

  • apps/playgrounds/node/index.ts
📚 Learning: 2025-11-24T16:04:00.957Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-11-24T16:04:00.957Z
Learning: Applies to **/*.{ts,tsx} : Use `ArkEnvError` for environment variable validation errors

Applied to files:

  • apps/playgrounds/node/index.ts
  • .changeset/cyan-loops-hear.md
📚 Learning: 2025-11-24T16:04:00.957Z
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/coding-guidelines.mdc:0-0
Timestamp: 2025-11-24T16:04:00.957Z
Learning: Applies to **/*.{ts,tsx} : Use PascalCase for type names (e.g., `ArkEnvError`)

Applied to files:

  • .changeset/cyan-loops-hear.md
🧬 Code graph analysis (2)
packages/arkenv/src/utils/coerce.ts (3)
packages/internal/keywords/src/index.ts (2)
  • maybeParsedNumber (12-17)
  • maybeParsedBoolean (28-32)
packages/internal/scope/src/index.ts (2)
  • $ (9-18)
  • $ (20-20)
packages/arkenv/src/type.ts (1)
  • type (3-3)
apps/playgrounds/node/index.ts (3)
apps/playgrounds/vite/vite.config.ts (1)
  • Env (11-16)
packages/vite-plugin/src/__fixtures__/basic/config.ts (1)
  • Env (3-6)
packages/arkenv/src/type.ts (1)
  • type (3-3)
🪛 LanguageTool
openspec/changes/coercion-public-api/proposal.md

[style] ~5-~5: To elevate your writing, try using a synonym here.
Context: ...codebase fragile to ArkType updates and hard to maintain as it requires deep knowled...

(HARD_TO)


[style] ~5-~5: Consider a different adjective to strengthen your wording.
Context: ...tes and hard to maintain as it requires deep knowledge of ArkType's node architectur...

(DEEP_PROFOUND)

🔇 Additional comments (17)
.changeset/cyan-loops-hear.md (3)

2-2: Patch version bump is appropriate.

The changeset correctly uses a patch bump for this internal refactoring that eliminates internal API dependencies without altering the user-facing API surface.


5-12: Changelog entry clearly documents the refactor.

The entry effectively communicates the architectural shift to public-API–based coercion, explains the mechanism (introspection via .in.json and .pipe()), and highlights key benefits. The structure and language are professional and appropriate for release notes.


7-9: Public API is stable—no user-facing changes detected.

The refactoring correctly uses only public ArkType introspection methods (.in.json and .pipe()) to implement the new Selective Path Coercion approach. All arkenv exports (createEnv, arkenv, EnvSchema, type, ArkEnvError) remain unchanged, and function signatures are compatible with previous versions. No internal API dependencies were found in the implementation.

.changeset/open-spiders-tan.md (1)

5-8: LGTM! Clear and well-documented breaking changes.

The changeset accurately describes the migration to central coercion using public ArkType APIs. The breaking changes are appropriately flagged, and the reference to the Selective Path Coercion layer aligns with the PR objectives.

apps/playgrounds/node/index.ts (3)

1-9: LGTM! Improved schema definition pattern.

Extracting the schema into a separate Env constant using type() is a best practice that improves reusability and enables introspection. This aligns with the public API approach and the patterns shown in other files (e.g., vite.config.ts).


11-14: Good demonstration of introspection capabilities.

The debug logging showcases the public API's introspection features (toJsonSchema() and toJSON()). This is appropriate for playground code and helps developers understand the new public API capabilities introduced by this PR.


15-16: LGTM! Consistent with schema refactor.

Passing the Env schema constant to arkenv() is consistent with the refactored pattern and enables better schema reuse and introspection.

openspec/changes/coercion-public-api/tasks.md (1)

1-16: LGTM! Comprehensive and completed task checklist.

The three-phase approach (Research, Implementation, Validation) is well-structured and covers all necessary aspects of the refactor. The inclusion of validation steps (tests, bundle size, documentation, playground verification) demonstrates thorough engineering discipline.

openspec/changes/coercion-public-api/design.md (1)

1-48: LGTM! Excellent design documentation.

The Pipeline Wrapper Pattern is well-articulated with clear rationale for key decisions:

  • Using in.json over toJsonSchema() for better fidelity and simpler traversal
  • Performance justification (one-time introspection at startup)
  • Pragmatic union handling strategy (loose coercion with validation)

The design aligns perfectly with the PR objectives of migrating to public APIs.

openspec/changes/coercion-public-api/specs/coercion-refactor/spec.md (1)

1-25: LGTM! Well-structured specification.

The specification properly follows the openspec format with:

  • Clear ADDED and MODIFIED requirement sections
  • Normative MUST language for requirements
  • Testable scenarios with Given/When/Then format
  • Concrete examples (nested numeric paths, pipeline coercion)

The requirements align with the PR objectives and design documentation.

.changeset/humble-lizards-judge.md (1)

5-9: LGTM! Clear documentation of keyword simplification.

The changeset accurately describes the shift from keyword-level coercion to central coercion:

  • Breaking changes are appropriately flagged
  • The rationale (delegating to arkenv's central coercion) is clear
  • Internal morphs (maybeParsedNumber, maybeParsedBoolean) supporting the new architecture are documented

This aligns with the overall PR objective of using public APIs for coercion.

packages/arkenv/ARKTYPE_INTERNALS.md (1)

1-32: LGTM! Excellent documentation of the migration.

This document provides comprehensive tracking of the internal API migration:

  • Clear status update indicating removal of internal dependencies
  • Historical context for future maintainers
  • Transparent acknowledgment of remaining internal usage ($.type.raw())
  • Well-articulated risk mitigation strategies

The documentation demonstrates good engineering discipline and will help with long-term maintainability.

packages/arkenv/package.json (1)

43-43: Use catalog protocol for @ark/schema to maintain consistency with other external dependencies.

The exact version "0.56.0" is inconsistent with the workspace pattern used throughout devDependencies. Other external packages like arktype, @types/node, and @size-limit/* reference the pnpm catalog via "catalog:". Since @ark/schema is not defined in the catalog (unlike arktype), either add it to the catalog in pnpm-workspace.yaml and update the reference to "catalog:", or use a flexible version range like "^0.56.0" to align with standard npm package management practices.

⛔ Skipped due to learnings
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/pnpm.mdc:0-0
Timestamp: 2025-11-29T08:00:08.044Z
Learning: Applies to {packages,apps,tooling}/**/package.json : When referencing workspace packages in dependencies, use the `workspace:*` protocol instead of version numbers
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Leverage ArkType's built-in types (e.g., `string.host`, `number.port`) where possible in environment schemas
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Keep environment variable schemas readable and TypeScript-like using ArkType syntax
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/monorepo.mdc:0-0
Timestamp: 2025-11-24T16:04:11.901Z
Learning: Applies to **/package.json : Use workspace:* protocol for workspace dependencies between packages
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/monorepo.mdc:0-0
Timestamp: 2025-11-24T16:04:11.901Z
Learning: Applies to packages/*/package.json : Packages in packages/ directory must be published to npm and require changesets for versioning, proper exports, and type definitions
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Use union types for enums in ArkType schemas (e.g., `"'dev' | 'prod'"`) instead of separate enum definitions
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/**/*.ts : Use ArkType's `type()` function to define schemas in environment variable definitions
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Applies to **/*.{ts,tsx} : Environment schema definitions should use built-in validators, ArkType string literals, and support default values in the schema pattern
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T22:11:39.931Z
Learning: Always run `pnpm changeset` for version bumps in published packages - never skip changesets
Learnt from: yamcodes
Repo: yamcodes/arkenv PR: 136
File: .changeset/vast-bananas-win.md:2-3
Timestamp: 2025-09-10T19:35:18.179Z
Learning: The arkenv package is currently in v0.x.x (pre-1.0) development phase, where breaking changes are acceptable in minor version bumps according to semantic versioning conventions.
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: ArkType validates environment variables at runtime and TypeScript types are inferred from the schema definition
Learnt from: CR
Repo: yamcodes/arkenv PR: 0
File: .cursor/rules/arktype.mdc:0-0
Timestamp: 2025-11-24T16:03:45.295Z
Learning: Applies to packages/arkenv/scope.ts : Define custom types in `scope.ts` using ArkType's scoped type system for reusability across schemas
Learnt from: yamcodes
Repo: yamcodes/arkenv PR: 498
File: apps/playgrounds/node/index.ts:2-2
Timestamp: 2025-12-05T20:33:10.676Z
Learning: ArkType 2.1.28+ supports Standard Schema specification, allowing interoperability with other Standard Schema-compliant validation libraries (e.g., Zod, Valibot) within the same schema definition
packages/internal/keywords/src/index.ts (1)

1-42: LGTM!

The loose morphs (maybeParsedNumber and maybeParsedBoolean) are well-designed for union coercion scenarios. They correctly pass through values they can't coerce, allowing other union branches to match. The port and host types appropriately leverage ArkType's built-in types per the coding guidelines.

packages/arkenv/src/utils/coerce.ts (3)

36-49: LGTM!

The boolean detection logic appropriately mirrors the numeric detection pattern and correctly handles domain, expression, and unit representations. The comment on line 47 clarifies union boolean handling.


97-102: Clarify sequence (array) coercion behavior.

When processing sequences, the path isn't extended with an index marker. This means array element coercion will share the same path as the parent. For typical env var use cases (comma-separated values parsed as arrays), clarify whether:

  1. The coercion applies at the array level before splitting, or
  2. Individual elements should be coerced (would need path extension like [*] or similar)

If intended, consider adding a comment explaining the expected behavior for array coercion in the env var context.


148-160: Clean implementation using public ArkType APIs.

The function correctly uses schema.in.json for introspection (public API), performs efficient early-return when no coercion is needed, and builds a proper pipeline for data transformation. The as never cast on line 160 aligns with the proposal's guidance for handling ArkType generics.

@yamcodes yamcodes changed the title Selective Path Coercion (100% Public API implementation) Selective Path Coercion (100% Public API Coercion implementation) Dec 22, 2025
@yamcodes yamcodes closed this Dec 22, 2025
@yamcodes
yamcodes deleted the coercion-less-internars branch December 22, 2025 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arkenv Changes to the `arkenv` npm package. docs Adds or changes documentation, or acts as documentation in and of itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant