refactor(core,app)!: align with @cartesi/rollup, drop the HTTP-era surface - #203
refactor(core,app)!: align with @cartesi/rollup, drop the HTTP-era surface#203tuler wants to merge 2 commits into
Conversation
…rface @deroll/core restated the rollup protocol in types that had drifted from the binding, and nine of them were leftovers of the removed Rollup HTTP Server transport with no consumers at all. @deroll/app wrapped a deliberately synchronous binding in an asynchronous facade. Keep both packages — the multi-handler loop and the interface that lets wallet and router plug into it are what deroll actually adds over Rollup.run(), which takes exactly one handler of each kind — but stop them restating the protocol. - core re-exports AdvanceRequest, InspectRequest, RollupRequest, Voucher, DelegateCallVoucher, BytesLike, AddressLike, U256Like and Hex from @cartesi/rollup instead of declaring its own copies, so they cannot drift. @cartesi/rollup becomes a peer dependency: the rollup device allows one open handle per process, so the tree must resolve to a single copy. viem is no longer a dependency of core. - delete RollupAdvanceRequest, RollupInspectRequest, RequestType, RequestData, RequestMetadata, NoticeResponse, ReportResponse and VoucherResponse. - flatten the advance request: AdvanceRequestData/AdvanceRequestMetadata become AdvanceRequest, carrying the metadata fields directly, which also drops the destructuring conversion in the request loop. - add registerException to App. NativeApp always implemented it, but it was missing from the interface createApp returns, so it was unreachable. - a handler exception now rejects the request and is emitted as a report, skipping the remaining handlers, instead of going to stderr and letting the next handler write state on top of a partially applied one. Reports survive a rejection, so the failure is visible from outside the machine. - outputs are synchronous, and notice/report payloads are passed directly rather than wrapped in an object. Handlers may still be async but need not be; the wallet and router handlers are now synchronous. Router.handler also reads its query straight out of the request Buffer instead of round-tripping through viem's toBytes, which only decoded correctly by accident. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ud9jF1bYpLMhJaJU8q1KDX
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 3a9efd3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
The string union was the last of the Rollup HTTP Server's vocabulary left in
the API. deroll v1 did not merely mirror it — it passed the handler's return
value straight into the transport:
const { data } = await this.POST("/finish", { body: { status }, ... });
status = await this.handleAdvance(...);
`RequestHandlerResult` was the `/finish` request body's `status` enum. With the
HTTP transport gone, handlers return a boolean, matching `finish({ accept })`
in the binding.
The words were misleading anyway. A handler returning "reject" never rejected
the input, it only declined it and passed it to the next handler; the input is
rejected only when no handler accepted. `true`/`false` describes that chain
honestly, where "accept"/"reject" claimed an authority a single handler in a
chain does not have.
The type is a strict boolean with no `void`: `Rollup.run` in the binding
accepts a request unless a handler returns false, whereas deroll rejects unless
a handler opts in, so a handler that falls off its end must be a type error
rather than a silent accept.
Also tightens the wallet deposit assertions from `toBeTruthy()` to
`toBe(true)`. They were vacuous before — both "accept" and "reject" are truthy
strings, so they passed whatever the handler returned.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ud9jF1bYpLMhJaJU8q1KDX
|
Closing in favor of #205. This PR kept That covered everything The work here is not lost — #205 contains these commits and builds on them. Left as a record of the alternative. Generated by Claude Code |
Why
This started as an evaluation of whether
@deroll/coreand@deroll/appstill earn their place now that@cartesi/rollupexists — it already ships aRollup.run({ advance, inspect })loop, and the two deroll packages are only ~230 lines combined.The conclusion was keep both, but stop them restating the protocol:
@deroll/appearns its place on multi-handler composition.Rollup.run()takes exactly one advance handler and one inspect handler;addAdvanceHandler/addInspectHandlerare what letwallet.handlerandrouter.handlerbe independently authored libraries sharing one loop. It also inverts the accept default (reject unless a handler opts in, which is the safer default for a rollup) and converts host-modeENODATAinto a clean exit.@deroll/coreearns its place as the composition seam — wallet and router depend on theAppinterface, not on the concrete app.core/src—request_type: "advance_state", nesteddata,NoticeResponse = { index },ReportResponse = Record<string, never>(still carrying its// XXX: should probably be 204comment) — all leftovers of the removed Rollup HTTP Server transport. The surviving types were near-duplicates of the binding's, but narrower and drifting.What changed
Protocol types come from
@cartesi/rollup.@deroll/corere-exportsAdvanceRequest,InspectRequest,RollupRequest,Voucher,DelegateCallVoucher,BytesLike,AddressLike,U256LikeandHexinstead of declaring its own copies, so the two cannot drift.viemis no longer a dependency ofcoreat all.core/src/types.tsis now mostly doc comments.Dead types deleted:
RollupAdvanceRequest,RollupInspectRequest,RequestType,RequestData,RequestMetadata,NoticeResponse,ReportResponse,VoucherResponse.The advance request is flat.
AdvanceRequestData/AdvanceRequestMetadata→AdvanceRequest, which also removes the destructuring conversion in the request loop.Outputs are synchronous, and notice/report payloads are no longer wrapped. Emitting an output is a device write, not I/O the event loop can interleave with —
finishpauses the entire guest. Vouchers keep their object argument, since they carry adestinationand optionalvaluebesides the payload.Handlers may still be
async— they are awaited — but no longer have to be. The wallet and router handlers are now synchronous.A handler exception rejects the request and is reported. Previously it went to
stderrand the next handler ran anyway, which could let a later handler write state on top of a partially applied one, and left the failure invisible from outside the machine. Now the input is rejected immediately, remaining handlers are skipped, and the error is emitted as a report — which survives the rejection.registerExceptionis now on theAppinterface.NativeAppalways implemented it, but it was missing from the interfacecreateAppreturns, so it was unreachable through the public API.Bonus fix:
Router.handlerwas doingbytesToString(toBytes(buffer)), which only round-tripped correctly becauseTextEncodercoerces aBufferviatoString(). It now reads theBufferdirectly.Two judgment calls worth reviewing
@cartesi/rollupis a non-optionalpeerDependencyof@deroll/core. This weakens the "no native addon in the pure packages" property — wallet and router now get the tarball in their tree. I chose it anyway because the binding is a singleton native resource (new Rollup()returns-EBUSYif one is already open), so two copies at different versions in one tree is a real failure mode; a non-optional peer forces exactly one hoisted copy. What survives is "the addon is never loaded by the pure packages," which is what matters for their tests. An optional peer would have preserved the stronger claim but broken type resolution when absent.The
Notice/Report/Exceptionwrapper types are gone. This is a larger API break than just droppingasync. Easy to revert tocreateNotice({ payload })if preferred.Verification
bun run build— 9/9 packages, including@deroll/docs, whose Vocs/twoslash snippets are genuinely typechecked. All 33 affected.mdxpages updated, plus the migration guide.bun run lintclean;tsc --noEmitonapps/examplesclean.minimalprints the flat request and exits 0;echoemits a correctNotice(bytes)output (c258d6e5selector,advance-0\npayload); a throwing handler produced a report file with the stack, no output files, and the second handler never ran — the new error policy confirmed at runtime, not just in types.bun run testat the repo root still fails on@deroll/genext2fs, whose addon needs a C toolchain the dev container lacks. Pre-existing and unrelated to this change; it aborts the turbo run, which is why wallet/router were run directly.A changeset (
minorfor core/app/router/wallet) documents each break with diffs, andCLAUDE.mdis updated.Generated by Claude Code