Skip to content

test(dsl): pin the DSL surface across all eight primitives - #27

Merged
sebyx07 merged 7 commits into
mainfrom
fix/action-fluent-surface-docs
Aug 10, 2026
Merged

test(dsl): pin the DSL surface across all eight primitives#27
sebyx07 merged 7 commits into
mainfrom
fix/action-fluent-surface-docs

Conversation

@sebyx07

@sebyx07 sebyx07 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Last task in the "DSL layer" PR group. dsl.test.ts already existed for action/query/jobs (job+task)/entity/policy/render (route) from prior sessions — this PR closes the one remaining gap: mutator had only behavioral tests, no shape+delegation pin.
  • Adds a "the mutator DSL surface" block to packages/action/src/dsl.test.ts (mutator lives in the action package, built on action()): exact member set (whole action façade + isMutator/conflict/local/server/describeMutator), delegation proofs for .local()/.server(), and a.tool().policy === a.policy for a mutator instance specifically — the same "one authz object across every surface" invariant already pinned for action/query/policy.
  • Bundles the prior commits in this PR group: action's fluent surface, routing every invocation through one core, the five DSL abstractions (defineApi/defineCatalogs/daysBetween/etc.), mirroring the façade on the other seven primitives, and re-exporting t from every primitive package.

Test plan

  • bun test packages/action/src/dsl.test.ts — 14/14 pass
  • bun run verify — 17/17 green
  • bun test — 3598 pass / 27 fail (unchanged pre-existing examples/dummy baseline, 0 framework regressions)

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Summary by CodeRabbit

  • New Features

    • Added centralized API registration for actions, mutators, and queries.
    • Introduced the rpc typed client and expanded API introspection.
    • Added timezone-aware calendar-day and billing-period utilities.
    • Added typed translation keys and streamlined catalog registration.
  • Improvements

    • Action authorization is now enforced consistently by handlers.
    • Publishing posts now uses POST /api/posts/publish.
    • Improved pluralization conventions and schema helper availability across packages.
  • Documentation

    • Expanded guidance for APIs, entities, jobs, routes, tasks, translations, and primitives.

sebyx07 and others added 6 commits August 10, 2026 10:37
The façade itself shipped in cdc5d42/1a536e8 — .input/.output/.policy/.mcp
lifted, .as/.tool/.openapi/.client/.job/.contract bound in facade.ts, .def
gone. What was missing was the reference an agent actually reads.

- wiki/Actions.md gains "The fluent surface", the section its sibling
  Queries-And-Live-Queries.md has had since query got the same treatment:
  one row per member, plus why `handle` is unreachable (X_ACTION_FOREIGN)
  and why registerActions() names the export in place.
- The six-artifacts table now names the method behind each projection —
  only .job() was named before.
- Fix the projected route: derivePath('publishPost') is
  POST /api/posts/publish, never /_x/action/publish-post. The wrong path
  was copied verbatim into the spec, the site, the quickstart curl and the
  reference app's MCP README; naming.test.ts pins the real one.
- Fix the introspection samples: MCP tool is publish_post, not publishPost,
  and both subcommands wrap the descriptor in the standard CLI envelope.

Verified against the running CLI (x actions list/describe --json) and a
scratch probe of all ten members, not read off the source.

Co-Authored-By: Claude <noreply@anthropic.com>
The invocation core (parse → policy → handle → parse output) and the private
declaration store already shipped; this closes the second authz path that
survived them.

- The HTTP pipeline evaluated an action's policy in its `authz` stage AND
  `invoke` evaluated it again. The stage runs before the handler, so it decides
  with `row: null` — every action declaring `row:` with a row-level rule 403'd
  for the row's own author and never reached the evaluation that had the row.
- `RouteMeta.enforcedBy: 'pipeline' | 'handler'` says which layer decides;
  `toRoute` sets `'handler'` and the stage stands down. `meta.policy` stays set,
  so `x routes` and the manifest still name the guard.
- `dev-hooks.ts` drops its action lookup — a decision it can no longer make
  correctly is a second authz system waiting for a caller.
- `index.test.ts` now enforces what CLAUDE.md only claimed: the barrel never
  re-exports `defOf`/`stashDef`/`hasDef`, and no projection carries `handle` out.
- New `http.test.ts` drives a row-level action over the real pipeline and counts
  evaluations: author 200, stranger 403, exactly one either way.

Both new gates negative-proved.

Co-Authored-By: Claude <noreply@anthropic.com>
defineApi, rpc, defineCatalogs, daysBetween — plus the seam the first of
them needed. defineService was already shipped; defineMail's app-side
signature was already fixed.

- action: defineApi({ actions, mutators, queries, llm }) is the app's one
  boot call. Names come from export names; the returned value is also the
  type rpc<Api['actions']>() is shaped from, so there is no second list.
- core: registrar.ts — the table one same-tier package reaches another
  through. action cannot import query sideways, so query announces
  registerQueries there and defineApi resolves it by kind. A missing
  registrar is X_REGISTRAR_MISSING, never a silent skip that drops every
  read; two different registrars for one kind is X_REGISTRAR_CONFLICT.
- action: createClient renamed to rpc. One name, no alias.
- i18n: defineCatalogs({ default, locales }) validates, flattens, registers
  under the framework catalog and configures the supported set in one call.
  currentTranslator renamed to useI18n<TCatalog>(); Translator is generic
  and TranslationKey<T> makes an unknown key a compile error. Bare
  Translator still defaults to string keys for ui and mail.
- time: daysBetween(from, to, zone) counts local calendar-day boundaries,
  signed, DST-correct. Zone required — no ambient default, anywhere.
- app: endOfBillingPeriod moves to @postly/core; a billing period is
  domain, not calendar time.
- app: catalog plurals were authored as nested { one, other } branches the
  runtime never probes, so four strings rendered as a miss in production.
  Moved to _one/_other leaves; the parity test that should have caught it
  was vacuous and now asserts it found some.

verify 17/17 green. +39 tests. Full suite failure set byte-identical to
baseline. Reference app typecheck 307 -> 302, every one of the five symbols
now resolving.

Co-Authored-By: Claude <noreply@anthropic.com>
The code shipped earlier; the reference manual named the fluent surface for
`action` and `query` only. Five primitives had a surface the manual never
mentioned, so an agent reading the wiki could not find it.

- job: `.enqueue()` `.as()` `.describe()` `.parse()` `.idempotencyKeyFor()`,
  and why `.as()` queues where an action's `.as()` runs — a job's execution
  surface IS the queue. `describe().steps` empty by design.
- task: `.entries()` `.enqueue()` `.describe()`, the occurrence-scoped key a
  tick uses versus the plain key a manual fire uses, and `tz` now checked
  against the runtime's IANA database. Dropped two `Fields` rows that named
  declaration keys `TaskDefinition` does not have (`queue`, `enabled`) —
  both are type errors today, two lines above "Nothing else."
- entity: the `$`-sigil members, and the type that explains them —
  `Entity = EntityCore & C`, so the entity IS its columns and `posts.name`
  must stay a column. Tenant resolution order written down.
- mutator: `.local()` `.server()` `.conflict`, and that `.server()` routes
  through the action's own callable, so the offline half gets the same
  parse -> policy -> handle -> parse core because it IS that call.
- route: the normalized descriptor — `meta()` always awaits, `budget` is
  always an object — plus the trap that normalization could have set, that
  `budget.js === undefined` still fails a hydrating `site/` route.
- The-Eight-Primitives: the rule itself, once, with each primitive's surface.

Two code fixes the docs pass surfaced:

- `isMutator` was fail-open: it accepted any function carrying the brand,
  with no declaration check, so a hand-rolled look-alike counterfeited the
  one primitive `isAction` would have refused. Now structural, like its twin.
- `packages/render/src/dsl.test.ts`: render was the only primitive package
  with a façade and no member-enumeration pin. Both new assertions were
  negative-proved — laundering the budget and adding a stray descriptor key
  each turn it red.

Co-Authored-By: Claude <noreply@anthropic.com>
The four primitive packages (action/query/jobs/entity) already re-exported
`t`; the rule stopped there. A `defineMail` template, a `defineAppMcp` tool
and an `llm()` call each declare a schema too, and each had to reach past
its package to `@ultimat3/schema` — a second import, and the ambiguity tax
axiom 1 exists to remove.

- mail/mcp/ai re-export `t` + `Infer` verbatim from `@ultimat3/schema`.
  All three already declared the dep, so no boundary changes (tier 4 → 0).
- index.test.ts per package asserts `t` is the SAME object, not a copy: a
  spread would typecheck and silently freeze `schemaProvider()` at import.
  Negative-proved — swapping the export for `{ ...schemaT }` turns it red.
- 5 reference-app files now take `t` from the package they declare in.
  `apps/web/**/entity.ts` deliberately stays on `@ultimat3/schema`: those
  declare no primitive, so schema already IS their one import.
- `@postly/mcp` drops its now-unused `@ultimat3/schema` dependency.
- `packages/{ai,mcp}/README.md` used `t` with no import at all — fixed.
- Rule stated once in `wiki/The-Eight-Primitives.md`, with why `policy`
  and `route` re-export nothing: neither primitive declares a schema.

Co-Authored-By: Claude <noreply@anthropic.com>
- mutator was the one primitive whose fluent façade the dsl.test.ts
  pattern never enumerated — action/query/jobs/entity/policy/render all
  had a shape+delegation pin, mutator only had behavioral tests.
- Adds it to packages/action/src/dsl.test.ts (mutator lives in the same
  package, built on action()): exact member set (action façade +
  isMutator/conflict/local/server/describeMutator), .local()/.server()
  delegation proofs, and a.tool().policy === a.policy for a mutator
  instance specifically.

Co-Authored-By: Claude <noreply@anthropic.com>
@sebyx07 sebyx07 added the claudetm Created by Claude Task Master label Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 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 recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a38d86ee-01fb-4a4d-84bf-581ec095357d

📥 Commits

Reviewing files that changed from the base of the PR and between 5e957a9 and 931275e.

📒 Files selected for processing (30)
  • packages/action/CLAUDE.md
  • packages/action/README.md
  • packages/action/src/define-api.test.ts
  • packages/action/src/define-api.ts
  • packages/action/src/dsl.test.ts
  • packages/action/src/http.test.ts
  • packages/action/src/index.test.ts
  • packages/ai/src/index.test.ts
  • packages/cli/src/dev-hooks.ts
  • packages/core/src/index.ts
  • packages/core/src/registrar.test.ts
  • packages/core/src/registrar.ts
  • packages/entity/src/tenancy.ts
  • packages/i18n/CLAUDE.md
  • packages/i18n/README.md
  • packages/i18n/src/define-catalogs.test.ts
  • packages/mail/src/index.test.ts
  • packages/render/CLAUDE.md
  • packages/render/src/dsl.test.ts
  • packages/render/src/errors.ts
  • packages/render/src/registry.ts
  • packages/time/src/cron-occurrence.ts
  • packages/time/src/zoned.test.ts
  • packages/time/src/zoned.ts
  • packages/time/src/zones.ts
  • wiki/Actions.md
  • wiki/Entities-And-Migrations.md
  • wiki/Error-Codes.md
  • wiki/Routes-And-Render-Modes.md
  • wiki/Scheduled-Tasks.md
📝 Walkthrough

Walkthrough

The pull request centralizes API registration, renames the typed client to rpc, moves action authorization into handlers, adds primitive registrars, introduces typed catalog registration and translation keys, adds timezone-aware billing utilities, and updates primitive exports, examples, tests, and documentation.

Changes

API and primitive platform

Layer / File(s) Summary
Centralized API registration
packages/action/src/define-api.ts, packages/core/src/registrar.ts, packages/query/src/registry.ts, examples/dummy/apps/web/api/index.ts
defineApi registers action-like and query modules, returns frozen typed maps, and derives the application Api type.
RPC client surface
packages/action/src/client.ts, packages/action/src/index.ts, examples/dummy/apps/web/shared/client.ts
createClient is replaced by rpc throughout the public API, tests, examples, and guides.
Handler-owned authorization
packages/http/src/router.ts, packages/http/src/pipeline.ts, packages/action/src/http.ts, packages/cli/src/dev-hooks.ts
Routes identify pipeline or handler enforcement. Handler-enforced actions bypass pipeline authorization and evaluate policy once after row loading.
Mutator surface validation
packages/action/src/mutator.ts, packages/action/src/dsl.test.ts, packages/action/src/mutator.test.ts
Mutators require both mutator branding and valid action structure. Tests cover local, server, MCP, policy, and rename behavior.

Typed catalogs and translations

Layer / File(s) Summary
Catalog registration workflow
packages/i18n/src/define-catalogs.ts, packages/i18n/src/index.ts, packages/i18n/src/define-catalogs.test.ts
defineCatalogs validates, loads, registers, and configures typed locale catalogs.
Typed translation access
packages/i18n/src/context.ts, packages/i18n/src/translator.ts, packages/i18n/src/translator.test.ts
useI18n replaces currentTranslator, and TranslationKey infers nested and plural translation keys.
Plural catalog migration
packages/i18n/catalogs/*.json, packages/i18n/src/catalog.test.ts
Plural entries use _one and _other leaf keys instead of nested objects.

Calendar billing calculations

Layer / File(s) Summary
Calendar-day utilities
packages/time/src/zoned.ts, packages/time/src/zoned.test.ts, packages/time/src/index.ts
daysBetween counts local calendar-day boundaries across timezone and DST changes.
Billing-period proration
examples/dummy/packages/core/src/billing.ts, examples/dummy/apps/web/app/orgs/service.ts, examples/dummy/packages/core/src/billing.test.ts
endOfBillingPeriod computes timezone-aware month boundaries, and organization upgrades use one captured instant for proration.

Primitive schema boundaries

Layer / File(s) Summary
Schema helper exports
packages/ai/src/index.ts, packages/mail/src/index.ts, packages/mcp/src/index.ts, packages/*/src/index.test.ts
AI, mail, and MCP expose the shared schema t and Infer through their public barrels.
Example import boundaries
examples/dummy/apps/web/app/*, examples/dummy/packages/mcp/*, examples/dummy/CLAUDE.md
Example declarations import schema helpers from owning primitive packages, while entity view schemas use @ultimat3/schema directly.

Route and fluent API contracts

Layer / File(s) Summary
Route descriptor contracts
packages/render/src/dsl.test.ts, packages/http/src/router.test.ts
Tests cover normalized route descriptors, metadata, budgets, validation, freezing, registry identity, and tags.
Primitive fluent surfaces
wiki/Entities-And-Migrations.md, wiki/Jobs-And-Workflows.md, wiki/Realtime.md, wiki/Scheduled-Tasks.md, wiki/The-Eight-Primitives.md
Documentation defines entity, job, mutator, task, and primitive projection contracts.
Action and route documentation
wiki/Actions.md, site/pages/*.md, packages/action/README.md
Documentation uses /api/posts/publish, fluent action projections, centralized registration, and structured introspection output.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: comprehensive DSL surface tests for all eight primitives.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/action-fluent-surface-docs

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

@developerz-ai

developerz-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

This PR looks ready — DSL surface pinned across all eight primitives, test plan passes. Consider applying the ready-to-merge label when you're ready to ship.

🤖 Posted by developerz.ai — the maintainer agent, not a human.

@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: 22

🤖 Prompt for all review comments with AI agents
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 `@packages/action/README.md`:
- Line 9: Update the Typed RPC client example in the README to use the fluent
action instance method, replacing action.client({ baseUrl }) with
publishPost.client({ baseUrl }); alternatively document only
rpc<Api['actions']>() if that is the intended API. Keep the example consistent
with the fluent API shown later in the document.

In `@packages/action/src/define-api.test.ts`:
- Line 1: Add a 1–4 line header comment before the imports in the define-api
test module, stating its single responsibility and why the tests exist; leave
the existing imports and test implementation unchanged.

In `@packages/action/src/define-api.ts`:
- Around line 83-85: Update the API construction around defineApi’s returned
actions and queries maps so they contain only entries accepted by
registerActions() and the query registrar; do not copy every export through
mergeModules(). Preserve registered primitive entries and prevent unregistered
helper exports or duplicate names from being silently exposed or overwritten,
using registrar results or explicit module validation.

In `@packages/action/src/dsl.test.ts`:
- Around line 184-190: Add a denied-context case to the test around
defineMutatorTarget, invoking target.server with a context that lacks
authorization and asserting it rejects with the expected authorization error.
Ensure this assertion verifies the call flows through the action’s callable
invoke path rather than directly through the declared server implementation,
while preserving the existing successful-result comparison.

In `@packages/action/src/http.test.ts`:
- Around line 1-5: Shorten the header comment in
packages/action/src/http.test.ts (lines 1-5) to no more than four lines,
retaining only the module’s single responsibility and why it matters; move the
detailed authorization rationale into the relevant test or authorization block.
Apply the same header reduction in packages/cli/src/dev-hooks.ts (lines 2-8),
preserving only its single responsibility and rationale.

In `@packages/action/src/index.test.ts`:
- Around line 46-62: Update the projection assertion in the “no projection
carries the declaration out with it” test to check direct property access for
handle and def, rather than relying on Object.keys enumerability. Preserve the
existing exception for route’s handler while ensuring any handle or def value
exposed by a projection causes the test to fail.

In `@packages/ai/src/index.test.ts`:
- Around line 1-3: Add a 1–4 line module header comment before the imports in
packages/ai/src/index.test.ts (lines 1–3) describing the test file’s
responsibility and purpose. Add an equivalent responsibility-and-purpose header
before the imports in packages/mail/src/index.test.ts (lines 1–3); both files
require direct changes.

In `@packages/core/src/registrar.ts`:
- Around line 1-8: Shorten the header in packages/core/src/registrar.ts lines
1-8 to 1-4 lines while retaining its single responsibility and module-boundary
rationale. Add a 1-4 line header at packages/core/src/registrar.test.ts line 1
describing the test module’s responsibility and why it exists.
- Around line 37-40: Update the X_REGISTRAR_CONFLICT error definition in the
registrar conflict path so fix is a single executable dependency-repair command
rather than explanatory text. Ensure the command directly deduplicates the
conflicting `@ultimat3/`${kind} package, and provide an equivalent --json form for
the CLI path while preserving the existing error context.

In `@packages/i18n/CLAUDE.md`:
- Around line 26-28: Update the plural-key convention in the documented rule to
use the CLDR n_other suffix instead of n_plural, keeping it consistent with
migrated catalogs, tests, and runtime probing. Remove the duplicate convention
rather than defining an alternative.

In `@packages/i18n/README.md`:
- Line 23: Update the README snippet label and referenced path from the
framework package barrel `packages/i18n/src/index.ts` to a generic application
module such as `src/i18n.ts`, while preserving the snippet’s application catalog
imports and type declarations.

In `@packages/i18n/src/define-catalogs.test.ts`:
- Line 1: Add a 1–4 line header comment before the imports in the
define-catalogs test module, explaining why these tests protect boot-time
catalog registration and stating the module’s single responsibility; do not
merely describe what the tests do.

In `@packages/render/src/dsl.test.ts`:
- Around line 1-8: Shorten the module header comment above the route DSL tests
to no more than four lines. Keep only the single responsibility of pinning the
normalized route descriptor shape and why that contract matters; remove detailed
implementation notes about specific tests, readers, and branching.
- Around line 86-88: Update the assertions around assertModeInvariants in the
route-mode tests to capture the thrown errors and verify their stable
X_ROUTE_MODE_INVALID code, rather than only checking that an exception occurs.
Apply the same error-code assertion to both referenced cases while preserving
the non-throwing expectation for the valid budgeted route.
- Around line 98-105: Update the test around registerRoute to add a negative
case passing the raw minimal declaration, and assert the documented route error
code. Keep the existing normalized config assertions, ensuring the test verifies
both accepted descriptors and rejection of raw declarations.

In `@packages/time/src/zoned.ts`:
- Around line 210-213: Update localDayEpoch to construct the UTC midnight
timestamp without Date.UTC’s 1900–1999 year remapping, using setUTCFullYear so
years 0000–0099 remain unchanged. Add a regression test covering the
0099-to-0100 boundary and verifying the resulting day difference is 1.

In `@wiki/Actions.md`:
- Line 76: Update the “Typed client function” example in Actions.md to use the
exposed map-wide rpc client and its Api['actions'] member instead of
api.publishPost(...). Keep publishPost.client({ baseUrl }) as the single-action
projection example.
- Around line 52-64: Clarify the lifted-field contract in the member table:
state that only input, output, policy, and mcp are facade members, while
cache.invalidates, rateLimit, and idempotent are available through describe() as
structured metadata only. Ensure the wording reconciles the “every declared
field is lifted” statement with this documented exception.

In `@wiki/Entities-And-Migrations.md`:
- Line 115: Update the documentation for the invalid-tenant X_INVARIANT_VIOLATED
error to require a stable cause: and fix: structure, with fix: instructing users
to set tenant to one of the listed valid columns or remove tenant to enable
inference.

In `@wiki/Error-Codes.md`:
- Around line 44-45: Update the X_REGISTRAR_MISSING and X_REGISTRAR_CONFLICT
entries in Error-Codes.md to derive the owner package from the reported
primitive kind, instruct users to import that package to announce its registrar,
and replace the hardcoded `@ultimat3/query` guidance. Make the conflict diagnosis
and resolution executable by using bun’s JSON package listing and a concrete
deduplication command.

In `@wiki/Scheduled-Tasks.md`:
- Line 25: Update the canonical scheduled-task example’s enqueue callback to
accept and use occurrenceMs, matching the enqueue contract defined near the diff
and ensuring catch-up payloads carry the scheduled occurrence rather than the
current wall-clock time.
- Around line 62-67: Reconcile the task metadata shape with the CLI contract:
update the `x tasks list --json` schema and example to remove `enabled`, or
retain `enabled` in the task metadata consistently. Ensure the task definition
and CLI output publish only one shape, defining the fact once and projecting it
everywhere.
🪄 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: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f408c38d-577b-45cd-9df5-0d4b4be76e55

📥 Commits

Reviewing files that changed from the base of the PR and between b2a1078 and 5e957a9.

📒 Files selected for processing (90)
  • docs/idea/02-primitives.md
  • examples/dummy/CLAUDE.md
  • examples/dummy/apps/web/api/index.ts
  • examples/dummy/apps/web/app/digest/mail.ts
  • examples/dummy/apps/web/app/orgs/entity.ts
  • examples/dummy/apps/web/app/orgs/service.ts
  • examples/dummy/apps/web/app/posts/entity.ts
  • examples/dummy/apps/web/app/posts/mail.ts
  • examples/dummy/apps/web/app/posts/prompts/summarize.ts
  • examples/dummy/apps/web/shared/client.ts
  • examples/dummy/packages/core/CLAUDE.md
  • examples/dummy/packages/core/src/billing.test.ts
  • examples/dummy/packages/core/src/billing.ts
  • examples/dummy/packages/core/src/index.ts
  • examples/dummy/packages/i18n/CLAUDE.md
  • examples/dummy/packages/i18n/README.md
  • examples/dummy/packages/i18n/catalogs/en.json
  • examples/dummy/packages/i18n/catalogs/es.json
  • examples/dummy/packages/i18n/src/catalog.test.ts
  • examples/dummy/packages/i18n/src/index.ts
  • examples/dummy/packages/mcp/CLAUDE.md
  • examples/dummy/packages/mcp/README.md
  • examples/dummy/packages/mcp/package.json
  • examples/dummy/packages/mcp/src/tools.test.ts
  • examples/dummy/packages/mcp/src/tools.ts
  • packages/action/CLAUDE.md
  • packages/action/README.md
  • packages/action/src/client.test.ts
  • packages/action/src/client.ts
  • packages/action/src/define-api.test.ts
  • packages/action/src/define-api.ts
  • packages/action/src/dsl.test.ts
  • packages/action/src/facade.test.ts
  • packages/action/src/http.test.ts
  • packages/action/src/http.ts
  • packages/action/src/index.test.ts
  • packages/action/src/index.ts
  • packages/action/src/mutator.test.ts
  • packages/action/src/mutator.ts
  • packages/ai/CLAUDE.md
  • packages/ai/README.md
  • packages/ai/src/index.test.ts
  • packages/ai/src/index.ts
  • packages/cli/src/dev-hooks.test.ts
  • packages/cli/src/dev-hooks.ts
  • packages/core/README.md
  • packages/core/src/error-codes.ts
  • packages/core/src/index.ts
  • packages/core/src/registrar.test.ts
  • packages/core/src/registrar.ts
  • packages/http/CLAUDE.md
  • packages/http/src/pipeline.test.ts
  • packages/http/src/pipeline.ts
  • packages/http/src/router.test.ts
  • packages/http/src/router.ts
  • packages/i18n/CLAUDE.md
  • packages/i18n/README.md
  • packages/i18n/src/context.test.ts
  • packages/i18n/src/context.ts
  • packages/i18n/src/define-catalogs.test.ts
  • packages/i18n/src/define-catalogs.ts
  • packages/i18n/src/index.ts
  • packages/i18n/src/translator.test.ts
  • packages/i18n/src/translator.ts
  • packages/mail/CLAUDE.md
  • packages/mail/README.md
  • packages/mail/src/index.test.ts
  • packages/mail/src/index.ts
  • packages/mcp/CLAUDE.md
  • packages/mcp/README.md
  • packages/mcp/src/index.test.ts
  • packages/mcp/src/index.ts
  • packages/query/CLAUDE.md
  • packages/query/src/registry.ts
  • packages/render/src/dsl.test.ts
  • packages/time/README.md
  • packages/time/src/index.ts
  • packages/time/src/zoned.test.ts
  • packages/time/src/zoned.ts
  • site/pages/index.md
  • site/pages/quickstart.md
  • wiki/Actions.md
  • wiki/Entities-And-Migrations.md
  • wiki/Error-Codes.md
  • wiki/Getting-Started.md
  • wiki/Jobs-And-Workflows.md
  • wiki/Realtime.md
  • wiki/Routes-And-Render-Modes.md
  • wiki/Scheduled-Tasks.md
  • wiki/The-Eight-Primitives.md
💤 Files with no reviewable changes (1)
  • examples/dummy/packages/mcp/package.json

Comment thread packages/action/README.md Outdated
Comment thread packages/action/src/define-api.test.ts
Comment thread packages/action/src/define-api.ts Outdated
Comment thread packages/action/src/dsl.test.ts
Comment thread packages/action/src/http.test.ts Outdated
Comment thread wiki/Actions.md Outdated
Comment thread wiki/Entities-And-Migrations.md Outdated
Comment thread wiki/Error-Codes.md Outdated
Comment thread wiki/Scheduled-Tasks.md
Comment thread wiki/Scheduled-Tasks.md
Correctness:
- defineApi builds its maps from the registrars' own results, not from
  every module export — a feature helper could otherwise sit in
  Api['actions'] as a client method nothing serves, and two modules'
  same-named helpers overwrote each other with no X_ACTION_DUPLICATE.
  ModuleRegistrar now returns RegisteredPrimitive; the type filters too.
- Date.UTC remaps years 0-99 onto 1900-1999, so daysBetween across the
  0099/0100 boundary returned -693959. One utcEpoch() in zones.ts now
  builds every calendar epoch in the package: localDayEpoch, toZoned's
  weekday, offsetAt, fromZoned's target, normalizeWall, cron occurrence.
  fromZoned({ year: 50 }) resolved to 1950 'exact' before this.
- registerRoute refuses a raw declaration with the new
  X_ROUTE_UNNORMALIZED instead of registering it and crashing later in
  describeRoutes() on config.budget.js.
- X_REGISTRAR_CONFLICT's fix was `bun pm ls | grep ... - then dedupe it`,
  which hands grep the prose as file arguments. Now one runnable command.
- Invalid `tenant:` now carries the edit that repairs it, not
  `x entity explain`, which describes invariants the author never wrote.

Tests that could not fail:
- .server() denial asserted through invoke (X_UNAUTHENTICATED); the two
  existing calls agreed even if it reached the declared half directly.
- Projections checked by property access, not Object.keys — a
  non-enumerable handle/def passed the old assertion.
- Route mode failures assert X_ROUTE_MODE_INVALID, not any throw; the
  "refuses a raw declaration" test now has that negative case.

Docs:
- action README + wiki reach projections through publishPost, not the
  action factory; typed client is rpc<Api['actions']>().
- Lifted-field contract made exhaustive (four members; the rest is
  describe()-only). i18n plural rule names the real CLDR suffix set.
- Scheduled tasks show occurrenceMs; `enabled` dropped — no such field.
- Four headers trimmed to the 1-4 line rule, four added.

Co-Authored-By: Claude <noreply@anthropic.com>
@developerz-ai

developerz-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

This PR looks ready — CI is green and there are no risk signals (patch impact, tests/docs for DSL surface pinning). Feel free to apply a ready-to-merge label when you're ready to ship!

🤖 Posted by developerz.ai — the maintainer agent, not a human.

@sebyx07
sebyx07 merged commit 7bfbcb1 into main Aug 10, 2026
9 checks passed
@sebyx07
sebyx07 deleted the fix/action-fluent-surface-docs branch August 10, 2026 17:37
@developerz-ai

developerz-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

🎉 Released v0.1.2!

🤖 Posted by developerz.ai — the maintainer agent, not a human.

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

Labels

claudetm Created by Claude Task Master

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant