Back to Plate

Slate v2 ScrubberApi Hard-Cut Ralplan

docs/plans/2026-05-20-slate-v2-scrubber-api-hard-cut-ralplan.md

53.0.627.7 KB
Original Source

Slate v2 ScrubberApi Hard-Cut Ralplan

Current Verdict

Hard cut public ScrubberApi.

Keep the internal need: Slate still needs a single internal debug-value formatter for error messages. The best target is not ScrubberApi.stringify(...) as public API and not raw ad hoc JSON.stringify(...) at every throw site. The best target is an internal formatter that is pure, deterministic, and cannot throw while building another error.

Accepted target:

ts
// internal only; not exported from the root `slate` package
formatDebugValue(value)

Rejected target:

ts
import { ScrubberApi } from 'slate'

ScrubberApi.setScrubber((key, value) => ...)
ScrubberApi.stringify(value)

Intent And Boundary

  • intent: remove a global mutable diagnostics/privacy hook from the raw Slate public API while preserving useful internal error formatting.
  • desired outcome: users no longer learn or depend on ScrubberApi; Slate internal invariant errors still include compact debug context through one internal helper.
  • in scope: packages/slate public export, docs page, legacy interface fixture, public-surface contract, internal error formatter replacement, DOM error formatting call sites.
  • non-goals: no new public diagnostics API, no app-level privacy redaction system, no product logging policy, no broad throw-policy rewrite.
  • decision boundary: this plan may decide the public cut and internal target shape; implementation belongs to later Ralph execution.
  • unresolved user-decision points: none for the architecture verdict.

Live Current State

Current live source exposes a public API:

  • .tmp/slate-v2/packages/slate/src/interfaces/scrubber.ts:1 defines Scrubber.
  • .tmp/slate-v2/packages/slate/src/interfaces/scrubber.ts:3 defines ScrubberInterface.
  • .tmp/slate-v2/packages/slate/src/interfaces/scrubber.ts:26 exports ScrubberApi.
  • .tmp/slate-v2/packages/slate/src/index.ts:130 exports ./interfaces/scrubber from the root slate package.
  • .tmp/slate-v2/packages/slate/test/public-surface-contract.ts:238 requires ScrubberApi as a root export.
  • .tmp/slate-v2/packages/slate/test/interfaces/Scrubber/scrubber.ts:1 preserves the legacy interface fixture.
  • .tmp/slate-v2/docs/api/scrubber.md:1 publishes a Scrubber API page.

Current docs are actively misleading:

  • .tmp/slate-v2/docs/api/scrubber.md:62 calls ScrubberApi.textRandomizer(...), but live ScrubberApi only exposes setScrubber and stringify.

Current internal usage is real and broader than the first obvious call sites:

  • .tmp/slate-v2/packages/slate/src/interfaces/transforms/general.ts:207 and :516 format merge-node and set-selection invariant details.
  • .tmp/slate-v2/packages/slate/src/interfaces/node.ts:528, :552, :564, :602, :760, and :876 format node/path lookup failures.
  • .tmp/slate-v2/packages/slate/src/transforms-node/merge-nodes.ts:168 formats merge-node kind mismatch errors.
  • .tmp/slate-v2/packages/slate/src/transforms-selection/select.ts:20 formats incomplete selection input.
  • .tmp/slate-v2/packages/slate/src/utils/modify.ts:97 and :119 format element/leaf lookup failures.
  • .tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts:800, :1041, :1150, :1162, and :1229 format DOM bridge resolution failures.
  • .tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts:155 defines SlateDOMResolutionError with raw details, which means ScrubberApi is not a complete privacy boundary anyway.

Current package-boundary fact:

  • .tmp/slate-v2/packages/slate/package.json:11 exports ./internal.
  • .tmp/slate-v2/packages/slate/src/internal/index.ts:1 owns the internal cross-package bridge.
  • .tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts:13 already imports Editor and getEditorLiveSelection from slate/internal.

That makes the best implementation target a shared internal helper exposed only through slate/internal for first-party packages, not a root slate export and not a documented user API.

Decision Brief

Principles:

  • raw Slate public API should expose editor primitives, not app logging policy.
  • diagnostics must not use global mutable state.
  • error formatting must not throw while constructing another error.
  • privacy claims must be real; a string-message scrubber is fake privacy if raw error details still carry values.
  • migration must be obvious: app logging redaction belongs in app logging.

Top drivers:

  • global mutable API is bad SSR/test/multi-editor DX.
  • current docs teach a method that does not exist.
  • internal call sites need a central formatter, not a public hook.

Viable options:

OptionProsConsVerdict
Keep ScrubberApi publicBackward-compatible with legacy Slate shape; app can redact stringified messages.Global mutable state, weak privacy boundary, stale docs, not editor architecture.reject
Rename to DebugValueApi publicMore honest name.Still exposes logging policy as raw Slate API and invites more surface area.reject
Add createEditor({ diagnostics })Per-editor, SSR-safe, more honest than global.Overbuilt now; privacy still leaks through thrown objects and app logs unless the whole error pipeline is designed.defer
Internal formatDebugValue onlyKeeps useful errors, removes false public promise, simplest migration.Users lose a legacy hook.choose

Chosen option: internal formatDebugValue only.

Consequences:

  • public ScrubberApi and Scrubber disappear from root exports.
  • docs delete the Scrubber API page and summary link.
  • tests stop preserving legacy Scrubber fixture parity.
  • internal error call sites keep readable debug snippets through one helper.
  • app privacy guidance, if documented later, should say to redact at the app logger/error boundary, not through Slate.

Public API Target

Cut:

ts
ScrubberApi
Scrubber
ScrubberInterface

No public replacement in this slice.

Do not add:

ts
createEditor({ diagnostics: { redact() {} } })

That may become valid only if Slate designs a full diagnostics pipeline, including thrown error details, browser bridge details, dev/prod behavior, and logging guidance. This slice should not invent that layer.

Internal Runtime Target

Add or reuse an internal helper owned by slate:

ts
const formatDebugValue = (value: unknown): string => {
  try {
    return JSON.stringify(value) ?? String(value)
  } catch {
    return Object.prototype.toString.call(value)
  }
}

Implementation may choose a stronger circular-safe implementation, but the required contract is:

  • no root package export, docs page, or app-facing replacement API
  • no global mutable configuration
  • deterministic output
  • safe fallback when JSON.stringify cannot serialize the value
  • used by all surviving Slate core error messages that currently call ScrubberApi.stringify

DOM package options:

  • preferred: add the helper in packages/slate/src/utils/format-debug-value.ts and export it only from packages/slate/src/internal/index.ts, then import it from slate/internal in slate-dom;
  • fallback only if build/package-boundary proof rejects the internal export: duplicate the same internal helper in slate-dom;
  • do not expose formatter as editor.api, extension API, root package API, or documentation.

Ecosystem Strategy Synthesis

SystemSourceMechanismAvoidsStealRejectSlate targetVerdict
Legacy Slate../slate/packages/slate/src/interfaces/scrubber.ts:1 and ../slate/docs/api/scrubber.md:62global Scrubber replacer for internal error stringificationleaking clear text in some error messagesthe desire for central formattingglobal mutable public API and stale textRandomizer docsinternal formatter onlydiverge
Slate v2 live.tmp/slate-v2/packages/slate/src/interfaces/scrubber.ts:26, .tmp/slate-v2/docs/api/scrubber.md:62API-suffixed copy of legacy scrubberlegacy parity driftsource-backed call-site inventorykeeping parity for parity's sakehard cut public, keep internal helperdiverge
ProseMirror../prosemirror-* grep found JSON formatting but no global scrubber/redaction APIeditor core does not expose logging policy as schema/editor APIpublic API bloatkeep diagnostics local to failuresapp-wide global redaction hookno public diagnostics APIagree
Lexical../lexical/scripts/error-codes/* uses build-time/dev invariant message handling; grep found no editor-level scrubber APIdiagnostics are build/tool/runtime concern, not editor document APIruntime public API pollutionkeep error policy separate from editor modelpublic mutable formatterinternal debug formatter onlypartial
Tiptap../tiptap grep found JSON examples/tests, no global scrubber/redaction APIextension DX focuses on commands/extensions, not logging policyproduct logging leaking into core editor APIdo not teach editor users a logging APIadding diagnostics to extension APIno public replacementagree

Issue Ledger Accounting

No fixed issue claim from this plan.

Related rows:

IssueClusterClaimWhyProof routeV2 sync ledgerPR line
#3948singletonNot claimedThe issue says Slate errors cannot be caught by error boundaries. Cutting ScrubberApi does not prove catchability or runtime recovery.no claim; repro-first onlydocs/slate-issues/gitcrawl-v2-sync-ledger.md:204 already says current repro requiredrelated matrix only
#3641singleton-dom-selectionRelatedPublic Scrubber cut is adjacent to error policy, but selection failure strictness belongs to DOM bridge policy..tmp/slate-v2/packages/slate-dom/test/bridge.ts; existing ledger rowdocs/slate-issues/gitcrawl-v2-sync-ledger.md:260 keeps cluster-syncedpreserve existing related row
#4643singleton-dom-selectionRelatedDOM point throwing and uncatchable selection failures need bridge/runtime proof, not message redaction..tmp/slate-v2/packages/slate-dom/test/bridge.ts; existing ledger rowdocs/slate-issues/gitcrawl-v2-sync-ledger.md:410 keeps cluster-syncedpreserve existing related row
#2039singleton-normalizationNot claimedBetter internal debug formatting is not named infinite-loop diagnostics.no claimdocs/slate-issues/gitcrawl-v2-sync-ledger.md:683 already not-claimedpreserve existing not-claimed row

ClawSweeper status: applied by ledger reuse for the related-issue discovery pass. The generated live ledger rows were read for #3948, #3641, #4643, and #2039; existing fork dossier / coverage matrix rows already cover #3641 and #4643; issue dossier and test-candidate rows cover #3948 and #2039. No ledger writes are needed in this pass because the classifications do not change and no fixed/improved issue claim is added.

Related issue discovery result:

  • #3948: live row read at docs/slate-issues/gitcrawl-live-open-ledger.md:165; dossier says weak repro and test candidate is blocked-on-repro, so Scrubber removal must not claim error-boundary catchability.
  • #3641: live row read at docs/slate-issues/gitcrawl-live-open-ledger.md:221; fork dossier keeps it cluster-synced under DOM selection failure policy, so Scrubber removal stays related only.
  • #4643: live row read at docs/slate-issues/gitcrawl-live-open-ledger.md:371; fork dossier keeps it cluster-synced under DOM point/selection bridge policy, so Scrubber removal stays related only.
  • #2039: live row read at docs/slate-issues/gitcrawl-live-open-ledger.md:644; dossier says this is normalizer diagnostics debt and the test candidate is not a first red test, so Scrubber removal stays not claimed.

Re-run ClawSweeper only if implementation changes thrown error behavior, catchability, normalizer diagnostics, or DOM bridge failure policy beyond removing the public Scrubber surface.

PR reference status: unchanged in current pass. If Ralph implements the cut, update docs/slate-v2/references/pr-description.md API-shape rows and remove any stale Scrubber public-surface language if present.

Issue-Ledger Pass Result

Broader keyword and cluster scan covered scrub, redact, privacy, exception, error boundary, diagnostic, stringify, uncatchable, and throw/error-policy wording across the generated live ledger, frozen ledger, manual v2 sync ledger, issue dossiers, test-candidate map, benchmark map, package-impact matrix, requirements file, coverage matrix, and PR reference.

Additional reviewed issues:

IssueClusterClaimWhyProof routeV2 sync ledgerPR line
#5202singletonNot claimedHistorical local install exception report. It is repo/tooling debt, not Scrubber/API architecture.no claimdocs/slate-issues/gitcrawl-v2-sync-ledger.md:271 already triage-closednone
#4971singletonNot claimedNull text is invalid document shape. Removing Scrubber does not change the valid Slate value contract.no claimdocs/slate-issues/gitcrawl-v2-sync-ledger.md:362 already triage-closednone

No benchmark issue is touched. docs/slate-issues/benchmark-candidate-map.md contains performance lanes, but this plan changes a cold-path diagnostics API surface only.

Issue-ledger conclusion: no fixed issue claim and no improved issue claim. Existing related rows stay as context; the hard-cut target is an API/DX cleanup with explicit non-claim accounting for adjacent error-policy issues.

Migration Backbone

Plate/plugin maintainer:

  • no adapter should wrap ScrubberApi;
  • product logging redaction belongs in the product logger/error boundary;
  • Plate can add its own logging redaction without raw Slate core API.

slate-yjs/collab maintainer:

  • no operation, snapshot, commit, history, or remote-apply semantics change;
  • collab proof impact is limited to public export/test churn.

Raw Slate app migration:

ts
// before
ScrubberApi.setScrubber((key, value) => ...)

// after
logger.configureRedaction(...)
// or:
JSON.stringify(value, replacer)

There is intentionally no Slate replacement.

High-Risk Pre-Mortem

  1. A user depended on ScrubberApi for production privacy and loses it.
    • answer: the existing hook was not complete privacy because thrown DOM errors can carry raw details; app logging redaction is the honest owner.
  2. Internal call sites get replaced with raw JSON.stringify and a circular value masks the original error.
    • answer: implementation must add a no-throw internal formatter.
  3. Public-surface tests pass but docs still teach Scrubber.
    • answer: implementation must delete docs/api/scrubber.md and the docs/Summary.md entry.

Slate Maintainer Objection Ledger

ChangeWho feels painLikely objectionSteelman antithesisTradeoffAnswerRejected alternativeMigrationProofVerdict
Cut public ScrubberApiapp authors using legacy privacy hook"You removed my only redaction escape hatch."Privacy-sensitive apps do need redaction.Apps must move redaction outside Slate.The current API is global mutable state and incomplete privacy; keeping it teaches a false guarantee.createEditor({ diagnostics.redact }) is more honest but overbuilt until error details/logging policy are designed.use app logger redaction or local JSON.stringify(value, replacer).public surface contract removes export; docs page deleted; internal formatter tests survive.keep
Replace internal ScrubberApi.stringifySlate core/DOM maintainers"This is churn for no runtime behavior."Central formatting is still useful.Implementation touches many throw messages.The payoff is removing public API without losing central error formatting.raw JSON.stringify everywhere would duplicate and can throw during error construction.none for users; internal only.package tests for formatter and representative existing error messages.keep

Confidence Scorecard

Initial current-state score: 0.87.

Related-issue pass score: 0.90.

Final planning score: 0.93.

DimensionScoreEvidence
React 19.2 runtime performance0.93No React render/subscription surface; vercel-react-best-practices skipped with reason; implementation target forbids editor diagnostics subscriptions.
Slate-close unopinionated DX0.95Public API becomes smaller; users keep normal JS/app logging instead of learning ScrubberApi; no replacement API is added.
Plate and slate-yjs migration backbone0.92No operation/snapshot/collab semantics touched; Plate owns product logging; slate-yjs impact is only export/test churn.
Regression-proof testing strategy0.90Plan names public-surface absence, docs deletion, legacy fixture removal, no-throw formatter safety, and representative node/DOM error tests for Ralph.
Research evidence completeness0.92Live Slate v2, legacy Slate, compiled research layer, local ProseMirror/Lexical/Tiptap grep, generated live ledger, dossiers, package matrix, requirements, and benchmark map were read.
shadcn-style composability/minimalism0.94No UI and no config object; one internal helper through existing slate/internal bridge is the smallest composable first-party shape.

Threshold note: this closes the planning/handoff objective, not the later Ralph implementation. .tmp/slate-v2 implementation proof is intentionally a Ralph gate and remains listed under Implementation Phases / Fast Driver Gates.

Applicable Implementation-Skill Review Matrix

LensApplicabilityFindingPlan delta
vercel-react-best-practicesskippedNo React render, subscription, effect, or browser event surface changes.No React-specific target.
performance-oracleskippedError formatting is cold-path diagnostics. The only perf rule is no editor/runtime subscription or per-render work.Keep helper pure and allocation-limited to throw paths.
performanceskippedNo production latency, virtualization, or large repeated-surface claim.No perf cohort gate.
tddappliedPublic API cut and formatter safety need tests, but do not write dead-code legacy-removal tests.Add public-surface absence, no-throw formatter, and representative error-message tests.
build-web-apps:shadcnskippedNo UI/editor chrome surface.No UI target.
react-useeffectskippedNo effects or external-system synchronization.No effect target.

Legacy Regression Proof Matrix

SurfaceLegacy behaviorTargetProof
Root slate exportlegacy Slate exports Scrubber; Slate v2 exports ScrubberApiroot package exports neither Scrubber nor ScrubberApiupdate packages/slate/test/public-surface-contract.ts
Docslegacy docs teach Scrubber and stale textRandomizerno Scrubber API page or summary entrydelete docs/api/scrubber.md; remove docs/Summary.md entry
Internal throw messageslegacy calls global scrubber from error stringsmessages use internal no-throw formatterunit test circular/unserializable formatting and representative existing throw sites
DOM bridge failuresSlate v2 formats DOM errors through root ScrubberApiDOM bridge imports shared helper from slate/internalfocused DOM bridge error test plus rg gate

Browser Stress / Parity Strategy

No browser stress gate is required for the planning pass because this cut does not change selection import/export, DOM repair, rendering, or input handling. If Ralph implementation changes DOM bridge throw semantics, run the focused .tmp/slate-v2 DOM bridge tests named by the implementation and keep issue claims conservative.

  • strengthened internal usage inventory from three example call sites to the complete current ScrubberApi.stringify replacement set;
  • chose the existing slate/internal package bridge as the first-party sharing mechanism for formatDebugValue;
  • changed ClawSweeper status from skipped to ledger-reused applied, with current live rows and existing dossier/coverage evidence named;
  • kept all issue claims conservative: no fixed issue, no improved issue, only related or not claimed rows;
  • added #5202 and #4971 as reviewed/not-claimed throw/exception keyword false positives;
  • kept createEditor({ diagnostics }) rejected/deferred because no current issue row proves a full diagnostics pipeline is required.

Implementation Phases

  1. Cut public surface:
    • delete .tmp/slate-v2/packages/slate/src/interfaces/scrubber.ts;
    • remove .tmp/slate-v2/packages/slate/src/index.ts:130;
    • remove ScrubberApi and Scrubber from public-surface contracts.
  2. Add internal formatter:
    • add internal formatDebugValue;
    • export it only through slate/internal for first-party package sharing;
    • replace every ScrubberApi.stringify import/call in slate and slate-dom;
    • formatter must not throw on circular/unserializable values.
  3. Clean tests/docs:
    • delete legacy packages/slate/test/interfaces/Scrubber/scrubber.ts;
    • delete docs/api/scrubber.md;
    • remove docs/Summary.md Scrubber entry;
    • add/update tests for public absence and internal formatter.
  4. Verify:
    • .tmp/slate-v2: focused slate public-surface contract;
    • .tmp/slate-v2: focused package tests covering representative error formatting;
    • .tmp/slate-v2: bun --filter slate typecheck;
    • .tmp/slate-v2: broader bun check if public export churn affects package graph.

Fast Driver Gates

  • cwd .tmp/slate-v2: rg -n "ScrubberApi|Scrubber\\b|setScrubber|interfaces/scrubber" packages docs site --glob '!site/out/**' returns only intentional changelog/archive references or zero current public references.
  • cwd .tmp/slate-v2: public-surface contract proves ScrubberApi is absent.
  • cwd .tmp/slate-v2: internal formatter test proves circular/unserializable value formatting cannot mask the original throw.
  • cwd .tmp/slate-v2: focused representative node/DOM error tests still pass.
  • cwd plate-2: node tooling/scripts/completion-check.mjs --id 019e46be-4ec4-7d11-bc6e-9fcf033a8803 reflects this review state.

Pass-State Ledger

PassStatusEvidence addedPlan deltaOpen issuesNext owner
current-state read and initial scorecompletelive ScrubberApi source, docs, public-surface contract, DOM error details, legacy Slate, local ecosystem grepaccepted hard cut public API plus internal formatter targetno implementation proof yetSlate Ralplan next pass
related issue discoverycompletegenerated live rows for #3948/#3641/#4643/#2039; fork dossier rows for #3641/#4643; issue dossier/test-candidate rows for #3948/#2039changed ClawSweeper from skipped to ledger-reused applied; kept all claims conservativeno fixed/improved issue claimSlate Ralplan next pass
issue-ledger passcompletekeyword/cluster scan across live/frozen/manual ledgers, package matrix, requirements, test candidates, benchmark candidates, coverage matrix, and PR referenceadded #5202/#4971 as reviewed/not-claimed false positivesno fixed/improved issue claimRalph implementation later
intent/boundary and decision briefcompleteexplicit intent, desired outcome, in-scope, non-goals, decision boundary, viable options, rejected alternatives, consequencesno unresolved user decisionnoneRalph implementation later
research/ecosystem synthesiscompletecompiled research plus local legacy Slate, ProseMirror, Lexical, Tiptap, and live Slate v2 sourcekept no public diagnostics API; chose slate/internal bridgeno contradictionRalph implementation later
pressure and objection passescompletehigh-risk pre-mortem, maintainer objection ledger, implementation lens matrix, migration backbonerejected public DebugValueApi and deferred diagnostics pipelineno unresolved P0/P1Ralph implementation later
closure gatescompletefinal planning score 0.93, pass ledger complete, continuation prompt present, completion state can closeplanning/handoff objective complete; implementation remains future worknoneRalph implementation later

Ralph Implementation Pass

Status: complete.

Implemented:

  • deleted the public Scrubber implementation, legacy fixture, docs page, and docs summary entry;
  • removed root/interface exports for ScrubberApi, Scrubber, and ScrubberInterface;
  • added internal formatDebugValue and exposed it only through slate/internal;
  • replaced all ScrubberApi.stringify throw-message call sites in packages/slate and packages/slate-dom;
  • updated the public-surface contract to require ScrubberApi absence and keep Scrubber banned as a bare root data-helper value;
  • added the internal formatter contract for circular values and JSON-serialization failures.

Diff-review result:

  • P0/P1/P2 findings: none.
  • Accepted risk: the .tmp/slate-v2 checkout already contains unrelated dirty changes in overlapping files such as packages/slate/src/index.ts, packages/slate/src/internal/index.ts, and packages/slate/src/interfaces/node.ts; this pass reviewed only the Scrubber hard-cut lines and left unrelated work intact.
  • Reference sweep: current ScrubberApi, setScrubber, textRandomizer, interfaces/Scrubber, and api/scrubber references are gone except the intentional public-surface absence guard. Broader Scrubber matches remain only in historical changelogs plus that guard.

Verification:

  • .tmp/slate-v2: bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/format-debug-value-contract.ts passed, 342 pass, 0 fail.
  • .tmp/slate-v2: bun test ./packages/slate-dom/test/bridge.ts ./packages/slate-dom/test/public-surface-contract.ts passed, 21 pass, 0 fail.
  • .tmp/slate-v2: bun --filter slate typecheck passed.
  • .tmp/slate-v2: bun --filter slate-dom typecheck passed.
  • .tmp/slate-v2: bun lint:fix ran and fixed formatting.
  • .tmp/slate-v2: post-lint focused tests passed, 363 pass, 0 fail.
  • .tmp/slate-v2: post-lint bun --filter slate typecheck and bun --filter slate-dom typecheck passed.
  • .tmp/slate-v2: bun check passed, including lint/typecheck and test suites.

Open Questions

None blocking the public hard-cut verdict.

Question that would change the future design, not this cut: should Slate ever own a full diagnostics pipeline with per-editor redaction, structured errors, and logging guidance? Current answer: no, not until a real downstream use case requires more than app-level logging redaction.

Final Handoff Outline

  • Public API: cut ScrubberApi, Scrubber, and ScrubberInterface.
  • Internal runtime: add root-private, no-throw formatDebugValue.
  • Docs: delete Scrubber API page; do not document a Slate replacement.
  • Tests: public-surface absence, formatter safety, representative error behavior.
  • Issues: no fixed claims; preserve related/not-claimed error-policy rows.
  • Migration: app logging redaction or local JSON replacer, not Slate API.

Final Completion Gates

Complete for the Slate Ralplan planning/handoff objective and the Ralph implementation slice.

Accepted final state:

  • hard cut public ScrubberApi, Scrubber, and ScrubberInterface;
  • keep only an internal root-private formatDebugValue helper shared through slate/internal for first-party packages;
  • do not add createEditor({ diagnostics }), DebugValueApi, editor APIs, or app-facing docs replacement;
  • no fixed or improved issue claims;
  • related/not-claimed issue accounting is recorded for #3948, #3641, #4643, #2039, #5202, and #4971;
  • implementation gates passed in .tmp/slate-v2, including bun check.