Skip to content

feat(pgpm-core): rebundleModule — per-chunk packageModule merge with byte-identical gate#1412

Merged
pyramation merged 1 commit into
mainfrom
feat/rebundle-module
Jul 22, 2026
Merged

feat(pgpm-core): rebundleModule — per-chunk packageModule merge with byte-identical gate#1412
pyramation merged 1 commit into
mainfrom
feat/rebundle-module

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Atom 4, second slice: turns the chunk plan from rebundlePlan (#1411) into actual merged migrations on disk. rebundleModule(sourceDir, { outputDir, ...strategy }) writes a rebundled module whose per-change files collapse to one migration per chunk, gated byte-identical against the original when packaged.

The merge reuses packageModule's exact engine rather than a second implementation. packageModule is refactored to extract that engine as mergeSqlStatements:

// shared by whole-module packaging and per-chunk rebundling
mergeSqlStatements(sql, { stripTransactions, echoExtensionName, pretty, functionDelimiter })
//   parse → filter(TransactionStmt/CreateExtensionStmt) → deparse → round-trip diff

packageModule(dir) = mergeSqlStatements(resolveWithPlan(dir), { stripTransactions: extension, echoExtensionName: extname })

Per chunk and per direction, rebundleModule merges the member scripts (transactions stripped) and re-wraps in one transaction — deploy/revert COMMIT, verify ROLLBACK — so each chunk deploys as exactly one transaction:

deploy/<chunk>.sql = BEGIN; <merge(members, deploy order)> COMMIT;
revert/<chunk>.sql = BEGIN; <merge(members, reverse order)> COMMIT;
verify/<chunk>.sql = BEGIN; <merge(members, deploy order)> ROLLBACK;

It then writes a chunk-quotient pgpm.plan (one change per chunk, deps = earlier chunk names, via generatePlanContent) and remaps tags onto their sealing chunk. The module stays the same extension — control/Makefile/package.json are copied verbatim, only the internal change set collapses.

Gate. rebundleModule returns invariant, and packaging both directories must match:

packageModule(sourceDir).sql === packageModule(outputDir).sql

This holds because merging strips the inner transactions and preserves statement order, so re-packaging strips the re-added wrappers and yields the same AST. Any deparse instability is caught by the existing round-trip diff.

Additive only; nothing calls rebundleModule yet. Follow-ups: classifier-driven boundaries (Atom 2 facts choosing seams) and the control-only cross-chunk dep mode for published module forks.

Test plan

  • 6 new rebundleModule tests (real DDL, no DB): per-chunk files + chunk-quotient plan, metadata copy, single-transaction merge (one BEGIN/COMMIT; verify ROLLBACK), byte-identical gate at folder and single-chunk dial positions, overwrite guard.
  • Existing packaging/modules/resolution suites: 62 tests + 29 snapshots green (confirms the packageModule extraction is behavior-preserving).
  • 11 rebundlePlan tests still green; tsc --noEmit and pnpm build clean.

Link to Devin session: https://app.devin.ai/sessions/ad40d16f38a349b48eb7ce9375e27e6e
Requested by: @pyramation

@pyramation pyramation self-assigned this Jul 22, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pyramation
pyramation merged commit a11485f into main Jul 22, 2026
14 checks passed
@pyramation
pyramation deleted the feat/rebundle-module branch July 22, 2026 05:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant