feat: declare the ledger handoff in the manifest so the kernel runs it (0.3.1) - #8
Merged
Conversation
…t (0.3.1) activate() calls ctx.sql.seedLedger before runMigrations, exactly as C11 documented -- but core runs permissions.sql.migrations itself, before activate(), so by the time this plugin got control all nine ledger rows were already written. The handoff could only report alreadySeeded, and skippedNoWitness -- the one alarm it exists to raise -- never fired. The 2026-08-21 acceptance run measured "0 seeded, 9 already seeded" on the exact upgrade the feature was built for, and nothing went red. Not fixable from inside the plugin: core calls the runner before handing over control, and the witnesses are knowledge only this plugin has. - permissions.sql.handoff: handoff-plan.json -- the kernel reads the plan and performs the handoff ahead of its own migration runner. The file is the one already in the ZIP, so an operator can still dry-run the exact plan with plugin-ledger-handoff.mjs before installing. - The activate() seedLedger call stays as the fallback. On a kernel that honours handoff it reports alreadySeeded, which is correct; on an older kernel it is the only thing that performs the handoff at all. - manifest.test.ts pins that handoff names a file the ZIP ships, and that the plan satisfies core's stricter reader: no unknown keys, no duplicates, under the size cap, filenames present in migrations/, and a ledger matching the manifest. Requires @omadia/plugin-api 1.6.0 (byte5ai/omadia#815). Older cores ignore the key and keep the previous behaviour. Refs byte5ai/omadia#814; epic byte5ai/omadia#470 C15.
This was referenced Aug 21, 2026
Weegy
added a commit
that referenced
this pull request
Aug 24, 2026
…16) (#17) package-lock.json recorded packages/plugin at 0.3.1 while its package.json moved to 0.3.4 across #8, #13 and #15. Nothing caught it: npm ci reconstructs the dependency tree, and a workspace member's own `version` field is not part of it, so the public lockfile claimed a version the plugin had not been for three releases. The one-command repair is the one that must not run. `npm install --package-lock-only` fixes the member entry and, in the same pass, rewrites the `../odoo-bot/middleware/packages/plugin-api` file: external from whatever core checkout sits next to this repo on the developer's disk (0.1.0 committed, 1.10.0 here) — machine state that must never land in a public lockfile. So: - Surgically bump ONLY the packages/plugin lockfile entry 0.3.1 -> 0.3.4. The external stays exactly as committed; no other member had drifted. - Add scripts/check-lock-sync.mjs: a read-only checker that asserts, for every workspace member (root included), lockfile version == package.json version, and prints the exact by-hand fix while forbidding the regeneration that leaks the local core checkout. It refuses any workspaces pattern it cannot safely expand -- outside-repo, a missing named member, or an unsupported glob -- rather than silently checking fewer members than the workspace has. - Wire it into `npm run package` (build-zip.mjs) and into CI before `npm ci`, where npm ci genuinely cannot see the drift. Add an `npm run check:lock` script. - Test packages/plugin/test/lockSync.test.ts covers discovery, drift, the external-is-never-a-member invariant, the error message, and that both wiring points are actually in place. Version stays 0.3.4 -- lockfile and tooling only, no release, no hub publish.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs byte5ai/omadia#814 (core PR byte5ai/omadia#815); epic byte5ai/omadia#470 C15.
Closes gap G7 of
docs/ACCEPTANCE-RUN-2026-08-21.md.The problem
activate()callsctx.sql.seedLedgerbeforerunMigrations, exactly as C11 documented. But core runspermissions.sql.migrationsitself, beforeactivate()(C7 — so "the tables exist" is an invariantactivate()can rely on). By the time this plugin got control, all nine ledger rows were already written:So the handoff could only ever report
alreadySeeded, andskippedNoWitness— the one alarm C11 exists to raise — never fired. Nothing went red:0 seeded, 9 already seededis indistinguishable from a healthy re-run.This was not fixable from inside the plugin. Core calls the runner before handing over control, and the witnesses are knowledge only this plugin has. There is no ordering the plugin can choose. Core PR byte5ai/omadia#815 adds
permissions.sql.handoff; this PR declares it.Changes
permissions.sql.handoff: handoff-plan.json— the kernel reads the plan and performs the handoff ahead of its own migration runner. The file is the one already in the ZIP (shipped since #6/#7 and listed infiles), unchanged: core's reader acceptspluginId/ledger/migrationsDirand ignores them precisely so one file serves both readers, which meansplugin-ledger-handoff.mjs --planstill dry-runs the exact plan an operator is about to install.The
activate()seedLedgercall stays, and the comment now says why. On a kernel that honourshandoffit reportsalreadySeeded— correct, the work is done, one read-only transaction. On a kernel that does not, it is the only thing that performs the handoff at all. Removing it would silently drop adoption on every older core; keeping it costs a log line on newer ones.0.3.0 -> 0.3.1 in both
package.jsonandmanifest.yaml(the hub reads the manifest;npm run packageaborts on drift — verified below).Tests
Two new cases in
test/manifest.test.ts, both pinning things the declaration newly makes load-bearing:handoffnames a plan the ZIP ships — and that it is inpackage.jsonfiles. Declaring a file the ZIP omits makes core refuse the activation outright, while every local test still passes. That is the failure mode this repo has been bitten by before (a declaration nothing reads), inverted.dir, whichSeedLedgerOptionsaccepts and so looks like it should work), no duplicate filenames, under the 128 KiB cap, every filename present inmigrations/,ledgermatching the manifest (a mismatch makes core warn that the previewed table is not the written one), and no shippeddryRun: true.The existing
ledgerHandoff.test.tsalready pins plan-vs-SEED_LEDGER_ENTRIES; these cover the manifest-to-plan link it does not.Verification
Controlled comparison, identical env (
DEV_PLATFORM_PG_TEST_URLonly), same worktree, built from clean each time:origin/mainExactly +2 tests and +2 passes — the two added above. The single cancellation (
purgeDevPlatformSchema — against Postgres) and the non-zero exit are pre-existing onorigin/mainand measured, not assumed: that suite needs a database carrying the plugin schema.npm run buildnpm run typechecknpm run packageomadia-dev-platform-0.3.1.zip, drift guard passed,handoff-plan.jsonpresent in the artifactBuilt against core PR byte5ai/omadia#815 via
OMADIA_CORE_DIR=... npm run link:core(plugin-api 1.6.0), which is the documented path for contract work on unmerged core branches.Merge order
This is safe to merge before the core PR: a kernel without C15 does not read
permissions.sql.handoff, and core's manifest loader warns-and-degrades on keys it does not know rather than rejecting the package. Such a kernel keeps the pre-0.3.1 behaviour exactly — theactivate()fallback does the handoff, as it does today.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.