Skip to content

feat(nextly): resolve field-group storage names from the catalog - #454

Merged
mobeenabdullah merged 26 commits into
mainfrom
feat/field-groups-storage-resolution
Aug 1, 2026
Merged

feat(nextly): resolve field-group storage names from the catalog#454
mobeenabdullah merged 26 commits into
mainfrom
feat/field-groups-storage-resolution

Conversation

@mobeenabdullah

@mobeenabdullah mobeenabdullah commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

What

The expand step of expand → migrate → contract for task 011. Every reader that addresses field-group storage now resolves the name from the database catalog instead of a constant, so one build reads both generations correctly.

This changes no storage. It adds no column, moves no data, and does not touch the merged migration engine. A database that has not migrated behaves exactly as before.

Why now

The three-dialect matrix (#448) found on its first real run that the migration renames things no runtime code can address. MIGRATION_TARGET.columnType appeared nowhere outside the migration folder, and FieldGroupRegistryService.registryTableName was a constant — so after a successful up, zero runtime schemas register and every field group reads as absent. B1 and B2 therefore could not ship independently. Expand is what separates them.

The rule

Read the migrated spelling only when the legacy one is absent.

Applied identically to the registry table and to each data table's discriminator. It is the order the migration itself uses, and the only one correct in both directions: up renames the registry last, down renames it first, so "legacy if present" always names the live object and never adopts one this migration did not move.

🔴 Resolved from the catalog, never from the marker. The marker is a recorded claim; the catalog is an observable fact. A database restored from backup can carry a marker that disagrees with its own storage — which is exactly the case a reader has to survive. guard.ts's resolveStorageVerdict is not the seam: it combines the marker with the probe and throws on every pair it cannot explain, so wiring it into the read path would turn a restored database from "reads correctly" into "refuses to boot".

Two design points worth reviewing closely

1. The Drizzle property key stays put; only the physical name moves. The adapter addresses columns by property key everywhere — db.select().from(tableObj) returns rows keyed by property, buildDrizzleWhere resolves getColumns(table)[cond.column], mapDataToColumnNames falls back to the key it was given. Keeping the key equal to STORAGE_FORMAT.columns.type therefore leaves every consumer of a component row unchanged, and keeps them correct through B2 when that constant flips.

The registry table gets no such luck: SchemaRegistry.registerStaticSchemas keys a table by getTableName(value) — the physical name — so there the handle is the name. Both the Drizzle object and the string that addresses it had to move together, which is why the dialect schemas became factories and both spellings are registered (for the schema registry only, never for a schema push).

2. The discriminator is resolved per table, not once per database. Three independent reasons, none hypothetical: the registry renames last, so mid-run and post-crash the two generations coexist; retargetName returns null for an author-named table, so its column moves while its table does not; and the DDL keeps writing the legacy spelling for a whole release, so a group created after a migration carries the legacy column while its siblings carry the migrated one.

typeColumn is required, not defaulted

A default would let a call site that never learned to resolve compile and then silently project a column that is not there — the exact failure this PR exists to remove. Making it required turned the type checker into the completeness proof: it named all seven call sites. Each one supplies either the resolved value, or STORAGE_FORMAT.columns.type where the code just wrote that DDL itself (the same constant read twice, not a guess). pushschema-pipeline.ts deliberately uses the constant — it builds the desired schema handed to drizzle-kit, so resolving there would make the desired shape follow the live shape and the diff always empty.

Tests

  • 20 unit tests on the resolver, four proven by breaking it: reversed preference order, collapsed per-table resolution to one global answer, cached the value instead of the promise, remembered a failed probe. Each killed exactly one test.
  • A new matrix test — reads content through the typed CRUD on either generation — the assertion this slice exists for, and the one the suite could not make before. The same code reads content through the typed ORM before and after the migration, choosing the discriminator from the catalog rather than being told which generation it is in. Proven load-bearing: making the resolution always answer the legacy spelling failed exactly and only that test, on both Postgres and SQLite, with the test count unchanged.
  • registerComponentSchemas gets a test that fails when the registry resolution is reverted to the constant.
  • The HMR path reuses the batched snapshot the reload already read rather than probing again — caught by an existing test asserting that reload issues one introspect call.

🔴 A gap this does NOT close, and it blocks the entry point

getCoreSchema(dialect) includes the field-group registry, and reconcileCore introspects CORE_TABLE_NAMES (which lists dynamic_components) and diffs. On a migrated database running this release's code, that diff sees the legacy registry missing and emits a CREATE — an empty duplicate. ensureSystemTables does the same via CREATE TABLE IF NOT EXISTS. On the next boot, legacy-first resolution would then pick the empty one.

It is not reachable today, because nothing migrates storage without the entry point, which does not exist. It is filed as the next slice and must land before the entry point: without it, the rollback safety that justified expand→migrate→contract does not exist. Keeping it out of this PR is deliberate — reconcileCore can drop tables and earns its own review rather than riding along.

Verification

  • pnpm build ✅ · pnpm lint exit 0
  • pnpm check-types --force: 8 errors, byte-identical to main's own (i18n/companion + collection-bulk test files, from fix(nextly): resolve companion readiness once and stop the read path aborting transactions #429, none touched here). Verified by running it on a clean origin/main worktree. This branch introduces none.
  • Unit suite 400 failed / 5891 passed / 42 skipped (6339), 400 unique failing test names, diffed at test-name level against a freshly measured baseline in its own installed-and-built worktree — empty in both directions.
  • Integration: 10 passed on Postgres 17 and 10 passed on MySQL (SQLite in-memory in both legs).

Summary by CodeRabbit

  • Bug Fixes

    • Improved compatibility with legacy and migrated database schemas, including renamed or case-sensitive registry tables.
    • Ensured dynamic field groups, components, collections, permissions, webhooks, reloads, and cleanup workflows resolve the correct tables and type columns.
    • Improved schema generation and migration behavior across PostgreSQL, MySQL, and SQLite.
    • Prevented unsupported filters and empty membership conditions from producing invalid query behavior.
  • Tests

    • Added coverage for migrations, mixed schema generations, storage-name resolution, caching, reloads, and typed CRUD operations.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@mobeenabdullah, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 21 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.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 612b58fa-cbdc-4798-8f71-a05b1ddd4ef1

📥 Commits

Reviewing files that changed from the base of the PR and between e124535 and e1fadbc.

⛔ Files ignored due to path filters (1)
  • .changeset/field-group-storage-name-resolution.md is excluded by !.changeset/**
📒 Files selected for processing (33)
  • packages/nextly/src/cli/commands/db-sync.ts
  • packages/nextly/src/cli/commands/dev-build.ts
  • packages/nextly/src/cli/commands/dev-server.ts
  • packages/nextly/src/cli/commands/prune.ts
  • packages/nextly/src/cli/commands/webhooks-prune.ts
  • packages/nextly/src/di/__tests__/load-dynamic-tables.test.ts
  • packages/nextly/src/di/load-dynamic-tables.ts
  • packages/nextly/src/di/register.ts
  • packages/nextly/src/dispatcher/handlers/component-dispatcher.ts
  • packages/nextly/src/domains/auth/services/permission-seed-service.ts
  • packages/nextly/src/domains/collections/services/collection-query-service.ts
  • packages/nextly/src/domains/field-groups/__tests__/entity-delete-field-group-data.integration.test.ts
  • packages/nextly/src/domains/field-groups/migration/__tests__/storage-migration.integration.test.ts
  • packages/nextly/src/domains/field-groups/migration/run.ts
  • packages/nextly/src/domains/field-groups/services/field-group-registry-service.ts
  • packages/nextly/src/domains/field-groups/services/field-group-schema-service.ts
  • packages/nextly/src/domains/field-groups/services/register-field-group-schemas.test.ts
  • packages/nextly/src/domains/field-groups/services/register-field-group-schemas.ts
  • packages/nextly/src/domains/field-groups/services/teardown-entity-field-group-data.ts
  • packages/nextly/src/domains/field-groups/storage/__tests__/resolve-storage-names.test.ts
  • packages/nextly/src/domains/field-groups/storage/registry-schemas.ts
  • packages/nextly/src/domains/field-groups/storage/resolve-storage-names.ts
  • packages/nextly/src/domains/schema/pipeline/managed-tables.test.ts
  • packages/nextly/src/domains/schema/pipeline/managed-tables.ts
  • packages/nextly/src/domains/schema/pipeline/pushschema-pipeline.ts
  • packages/nextly/src/init/__tests__/reload-config.test.ts
  • packages/nextly/src/init/__tests__/stored-field-group-tables.test.ts
  • packages/nextly/src/init/reload-config.ts
  • packages/nextly/src/schemas/dynamic-field-groups/index.ts
  • packages/nextly/src/schemas/dynamic-field-groups/mysql.ts
  • packages/nextly/src/schemas/dynamic-field-groups/postgres.ts
  • packages/nextly/src/schemas/dynamic-field-groups/sqlite.ts
  • packages/nextly/src/shared/base-registry-service.ts
📝 Walkthrough

Walkthrough

The PR resolves legacy and migrated field-group registry tables and discriminator columns from live catalog metadata. It updates schema registration, runtime operations, queries, CLI commands, reload handling, migration cache invalidation, and regression tests.

Changes

Field-group storage resolution

Layer / File(s) Summary
Storage resolution and schema factories
packages/nextly/src/domains/field-groups/storage/*, packages/nextly/src/schemas/dynamic-field-groups/*, packages/nextly/src/shared/base-registry-service.ts
Catalog helpers resolve registry and discriminator names. Dialect registry schemas accept physical table names. Registry services use resolved tables.
Runtime schema registration
packages/nextly/src/domains/field-groups/services/*, packages/nextly/src/di/register.ts, packages/nextly/src/dispatcher/handlers/component-dispatcher.ts, packages/nextly/src/init/reload-config.ts, packages/nextly/src/domains/schema/pipeline/pushschema-pipeline.ts
Runtime schemas receive resolved discriminator columns. Registration, reload, component dispatch, and metadata writes support migrated storage names.
Loading, querying, and command integration
packages/nextly/src/di/load-dynamic-tables.ts, packages/nextly/src/domains/collections/services/collection-query-service.ts, packages/nextly/src/domains/auth/services/permission-seed-service.ts, packages/nextly/src/domains/field-groups/services/teardown-entity-field-group-data.ts, packages/nextly/src/cli/commands/*
Loaders, collection filters, permission seeding, teardown, and CLI schema registration resolve registry aliases and table-specific discriminator columns.
Migration invalidation and regression coverage
packages/nextly/src/domains/field-groups/migration/*, packages/nextly/src/domains/field-groups/storage/__tests__/*, packages/nextly/src/domains/field-groups/services/register-field-group-schemas.test.ts, packages/nextly/src/di/__tests__/load-dynamic-tables.test.ts, packages/nextly/src/init/__tests__/*
Migrations clear cached storage names. Tests cover migrated and legacy tables, casing, caching, failed catalog reads, runtime registration, reload behavior, and typed CRUD across migration generations.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant StorageNameResolver
  participant Catalog
  participant RuntimeSchemaService
  participant SchemaRegistry

  Caller->>StorageNameResolver: resolve registry and discriminator names
  StorageNameResolver->>Catalog: read tables, columns, and identifier rules
  Catalog-->>StorageNameResolver: return live storage metadata
  StorageNameResolver-->>Caller: return physical names
  Caller->>RuntimeSchemaService: generate schema with resolved typeColumn
  RuntimeSchemaService-->>Caller: return dialect schema
  Caller->>SchemaRegistry: register schema and registry aliases
Loading

Possibly related PRs

Suggested labels: scope: db-adapter

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed and relevant, but it omits required template sections for change type, changeset confirmation, checklist, and test-plan checkboxes. Add the template headings and complete the type, related issues, changeset and semver, test-plan, checklist, and reviewer-note sections.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: resolving field-group storage names from the database catalog.
Docstring Coverage ✅ Passed Docstring coverage is 82.61% 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.
✨ 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/field-groups-storage-resolution

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.

@github-actions github-actions Bot added scope: core nextly type: docs Documentation only labels Jul 31, 2026
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@greptileai

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 22 minutes.

@pkg-pr-new

pkg-pr-new Bot commented Jul 31, 2026

Copy link
Copy Markdown

Open in StackBlitz

@nextlyhq/adapter-drizzle

npm i https://pkg.pr.new/@nextlyhq/adapter-drizzle@e1fadbc

@nextlyhq/adapter-mysql

npm i https://pkg.pr.new/@nextlyhq/adapter-mysql@e1fadbc

@nextlyhq/adapter-postgres

npm i https://pkg.pr.new/@nextlyhq/adapter-postgres@e1fadbc

@nextlyhq/adapter-sqlite

npm i https://pkg.pr.new/@nextlyhq/adapter-sqlite@e1fadbc

@nextlyhq/admin

npm i https://pkg.pr.new/@nextlyhq/admin@e1fadbc

@nextlyhq/admin-css

npm i https://pkg.pr.new/@nextlyhq/admin-css@e1fadbc

@nextlyhq/blocks-engine

npm i https://pkg.pr.new/@nextlyhq/blocks-engine@e1fadbc

create-nextly-app

npm i https://pkg.pr.new/create-nextly-app@e1fadbc

nextly

npm i https://pkg.pr.new/nextly@e1fadbc

@nextlyhq/plugin-form-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-form-builder@e1fadbc

@nextlyhq/plugin-page-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-page-builder@e1fadbc

@nextlyhq/plugin-sdk

npm i https://pkg.pr.new/@nextlyhq/plugin-sdk@e1fadbc

@nextlyhq/plugin-seo

npm i https://pkg.pr.new/@nextlyhq/plugin-seo@e1fadbc

@nextlyhq/storage-s3

npm i https://pkg.pr.new/@nextlyhq/storage-s3@e1fadbc

@nextlyhq/storage-uploadthing

npm i https://pkg.pr.new/@nextlyhq/storage-uploadthing@e1fadbc

@nextlyhq/storage-vercel-blob

npm i https://pkg.pr.new/@nextlyhq/storage-vercel-blob@e1fadbc

@nextlyhq/ui

npm i https://pkg.pr.new/@nextlyhq/ui@e1fadbc

commit: e1fadbc

@mobeenabdullah
mobeenabdullah force-pushed the feat/field-groups-storage-resolution branch from cb89a17 to 10ebc85 Compare July 31, 2026 21:17
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

Rebased onto main b8e54d563 (#453, which repairs the i18n/bulk typecheck errors) and re-verified by build. Head 10ebc8541.

check-types is now a real gate again, and this branch clears it. Main was red on typecheck when this PR was opened — 8 errors from #429 — so the PR body reported "identical to main's own" rather than a clean run. #453 fixed those, and on the rebased branch:

  • pnpm build ✅ · pnpm check-types --force 19/19, zero errors ✅ · pnpm lint exit 0
  • Unit suite 400 failed / 5891 passed / 42 skipped (6339), 405 raw FAIL lines / 400 unique, diffed at test-name level against a freshly measured b8e54d563 baseline in its own installed-and-built worktree (400 failed / 5870 passed / 42 skipped) — empty in both directions. The branch adds 21 passing tests and no failures.
  • Integration 10 passed on Postgres 17 and 10 passed on MySQL (SQLite in-memory in both legs).

No unresolved threads. CodeRabbit is rate limited and has not actually reviewed — its note says so even though its check reports pass. Not merged.

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@greptileai

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 15 minutes.

@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: 10ebc85413

ℹ️ 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 packages/nextly/src/di/register.ts Outdated
Comment thread packages/nextly/src/domains/field-groups/storage/registry-schemas.ts Outdated
Comment thread packages/nextly/src/dispatcher/handlers/component-dispatcher.ts Outdated
Comment thread packages/nextly/src/cli/commands/db-sync.ts
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

Round update, head efefaee22. All six Codex findings verified against the code and upheld — every one was real. This was the best review round of the program.

# Finding Why it mattered
P1 Boot pass addressed the legacy registry The exact failure this PR exists to prevent, in the one place that matters most. loadDynamicTables swallows a failed read as the fresh-database case, so a migrated database registered zero component tables and raised nothing
P1 Bare Error for an unsupported dialect AGENTS.md requires NextlyError in packages/nextly/**
P1 Post-apply metadata write DDL already committed, write treated as non-fatal, runtime refresh masks it — breaks only after a restart
P1 Orphan delete in handleRemovedComponents Runs after nested instances and localized data are torn down, so it fails once content is already gone: partial data loss
P1 buildComponentFieldConditions raw predicate The one place the stable property key does not reach — it emits the name it is handed
P2 getAllComponentSlugs via the static Drizzle object Error swallowed by cleanupOrphanedPermissions, so cleanup reports nothing while treating every field-group permission as orphaned

The pattern I got wrong, and it is worth stating plainly: I swept for the places that read field-group storage and stopped there. Four of these six are writes and deletes, and three of them fail silently because the surrounding code already treats that failure as benign. Resolution has to cover everything that addresses the storage, not everything that reads it — and a swallowed error is not a smaller bug than a thrown one, it is a larger one.

Finding 5 needed a structural change worth reviewing: the value condition was built once per filter, above the per-table loop. That cannot be right when the column name is per table, since a dynamic-zone filter spans several tables the migration may have moved independently. The switch is now a module-level helper called inside the loop. Same logic, evaluated per table.

Verification: build ✅ · check-types --force 19/19 ✅ · lint exit 0 ✅ · unit 400 failed / 5894 passed / 42 skipped (6342), 400 unique, diffed at test-name level against a freshly measured b8e54d563 baseline — empty both ways · integration 10 passed on Postgres 17 and 10 passed on MySQL. Three new load-bearing tests on the boot path; breaking the resolution failed exactly one, count unchanged at 16.

All six threads replied and resolved. Not merged.

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@greptileai

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 46 minutes.

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

ℹ️ 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 packages/nextly/src/domains/collections/services/collection-query-service.ts Outdated
Comment thread packages/nextly/src/di/register.ts Outdated
@mobeenabdullah
mobeenabdullah force-pushed the feat/field-groups-storage-resolution branch from efefaee to 0ac8019 Compare July 31, 2026 21:57
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

Rebased onto main 80fdee610 (#455, #445, #452 — 29 files, +1641 in packages/nextly) and re-verified by build. Head 0ac8019d2.

  • pnpm build ✅ · pnpm lint exit 0
  • Unit 400 failed / 5944 passed / 42 skipped (6392), 400 unique, diffed at test-name level against a freshly measured 80fdee610 baseline in its own installed-and-built worktree (400 failed / 5920 passed) — empty in both directions. This branch adds 24 passing tests and no failures.
  • Integration 10 passed on Postgres 17 and 10 passed on MySQL.

⚠️ check-types is red on main again — 16 errors, all in companion-transition.integration.test.ts, arriving with #452. Measured on a clean 80fdee610 worktree and diffed: byte-identical to this branch's, so #454 introduces none. Flagging rather than touching it; it is another session's.

All threads resolved. Waiting on Codex to review this head before merging.

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@greptileai

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 38 minutes.

@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: 0ac8019d28

ℹ️ 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 packages/nextly/src/di/register.ts Outdated
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

Round update, head 26f326931. All three Codex findings on 0ac8019d2 verified and fixed.

P1 — discriminator for an updated code-first table. The serious one, and I had written a comment there asserting the opposite: "This table was created by the DDL a few lines above… not a guess." One grep disproves it — generateMigrationSQL emits CREATE TABLE IF NOT EXISTS (field-group-schema-service.ts:199), so a component whose fields changed arrives with its table untouched, and the hard-coded descriptor then overwrote the boot pass's catalog-resolved registration. Now resolved, with a load-bearing test.

P2 — skip introspection for non-type filters. resolveComponentTypeColumns now returns empty unless a filter carries isComponentTypeFilter. It was spending per-table column/index catalog queries (a PRAGMA each on SQLite) on every component-filtered read for a value the predicate never consulted.

P2 — batch the boot introspection. The callback now collects rows and registers in a second pass with one resolveTypeColumns for the whole set. I had conflated the unit of resolution (per table — genuinely required, since the registry renames last and an author-named table is never renamed while its column always is) with the unit of query. resolveTypeColumns takes a list precisely so those can differ.

Verification: build ✅ · check-types --force byte-identical to main's 16 pre-existing (from #452; verified on a clean 80fdee610 worktree — this branch introduces none) ✅ · lint exit 0 ✅ · unit 400 failed / 5945 passed / 42 skipped (6393), 400 unique, diffed at test-name level against a freshly measured baseline — empty both ways · integration 10 passed on Postgres 17 and 10 passed on MySQL.

All threads resolved. Re-triggering Codex on this head; merging once it reports clean, per the founder's grant.

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

An exact spelling comparison called a folded registry absent, which let the
derived legacy names be declared usable and the reload build empty tables
beside the populated migrated ones.
A group whose schema change was skipped had its new fields persisted anyway,
so the registry described columns the table does not have and the next boot
built a runtime schema that failed every read and write for it.
Prefix discovery is the only route to an orphan whose registry row is what
went missing, and after the storage migration a generated table carries the
migrated prefix rather than the legacy one.
The count over a component filter repeated the registry lookup and the
catalog introspection the list had already done for the same request.
The orphan sweep reaches field-group tables by walking the catalog, so a
migrated localized group's companion entered it and was probed as an instance
table for an id column it does not have, failing every entity delete.
A catalog read that failed sent every field group to the legacy discriminator,
which on migrated storage names a column none of those tables have, so all
field-group reads and writes failed until the process restarted.
@mobeenabdullah
mobeenabdullah force-pushed the feat/field-groups-storage-resolution branch from 2862aca to 2ccdc53 Compare August 1, 2026 02:04
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

Rebased onto origin/main = 55dc55207 and re-verified by build. New head 2ccdc5356 (25 commits). No code changes in this push.

Main's only new commit (#462) touches two *.integration.test.ts files, which packages/nextly/vitest.config.ts:38 excludes from the unit run, so the unit baseline provably cannot have moved and was not re-measured on that basis.

Verification on this head: pnpm build clean, pnpm check-types --force 19/19, pnpm lint exit 0. Unit 400 unique / 405 raw, diff empty both ways against the cbaa8d8ed baseline, 6035 passing. Field-group integration 30 passed Postgres 17 / 27 passed MySQL.

The three webhook outbox failures I reported last round as pre-existing on main are now green here, since #462 is exactly their fix: outbox-capture and singles-outbox both pass on this head.

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@greptileai

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 40 minutes.

@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: 2ccdc53568

ℹ️ 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 packages/nextly/src/domains/field-groups/storage/resolve-storage-names.ts Outdated
A migrated database holds both discriminator spellings at once, since a group
created after the migration carries the legacy column beside migrated siblings,
so no answer derived from the database as a whole is right for every table.
The batch probe now falls back to asking per table and leaves out what it
cannot read, and the boot pass skips those rather than naming a column that
was never verified.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: e1fadbc4a8

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

@mobeenabdullah
mobeenabdullah merged commit 11f75b5 into main Aug 1, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: core nextly type: docs Documentation only

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant