Skip to content

Latest commit

 

History

History
723 lines (634 loc) · 54.8 KB

CELLSCRIPT_AUTHORING_IMPLEMENTATION.md

File metadata and controls

723 lines (634 loc) · 54.8 KB

Authoring Implementation and Production Acceptance

Objective and current state

Implement the adopted authoring target to production quality, with no loss of Edition 2026's supported functionality or feature completeness. This includes the complete language and toolchain, not only a Token example or acceptance of old source text.

The bounded 0.30 release scope is recorded in the capability ledger and release notes. This wider authoring plan is not a claim that all proposed 1.0 features are complete. The source contract advances from the recorded authoring1 and 0.30-dev1 development identities to cellscript-source-semantics-2027-0.30-v1; the compiler version is 0.30.0 while existing single-entry payload/placement ABIs are unchanged. Explicit persistent Type policies have a separate, opt-in cellscript-policy-witness-v1 envelope. The implementation may become the next stable release without publishing a stable 0.26 line. The 0.30 scope and its broader Rust-comparable business acceptance portfolio are tracked in the 0.30 capability closure RFC; neither the release name nor this development evidence changes a compatibility identity.

Issue #23 selects the public-generics Proposal A for 0.30. Public value templates and pure functions remain importable across packages, fixed_value normalizes the common six-ability contract, omitted aggregate abilities are derived from fields, and the compiler, Registry, artifact checker, CLI, LSP, editor, and browser metadata path share one canonical interface model. This closes one language-design slice. The bounded 0.30 portfolio and its completed release-candidate checks are recorded in the dated issue audit; the wider authoring objective below remains a separate contract.

The issue #23 acceptance boundary passed dev, ci, and backend on 2026-09-08 at 69488316. The backend evidence includes the clean-source CKB production/stateful acceptance harness.

The first implementation step restores familiar authoring over the shared declaration, type, value, and statement grammar. Ordinary action/lock bodies may omit verification; the formatter currently emits the established explicit marker. Multiple source entries, default parameter provenance, read references, and existing lifecycle operations are retained. A legacy consume keeps its existing semantics and evidence classification. It does not acquire a native retirement or pooled-accounting guarantee.

The bounded native preview4 grammar remains accepted as an implementation reference. It is not the final authoring surface. Complete shared-policy product support, executable branch-alternative successors, the remaining relation policies, and graph-wide schema-acknowledgement integration are still required. Neither reuse of the 2026 parser kernel nor successful scoped action ELFs satisfies those requirements.

Completion requirements

This table covers the wider authoring objective, including constructor and ABI work outside the accepted bounded 0.30 portfolio. Every row needs current-state evidence before that wider objective can be called complete. A passing test must actually exercise the stated behavior. Missing evidence, a metadata label, and an unsupported construct that rejects safely are not implementation of a required supported feature.

Requirement Required implementation and evidence Current disposition
Complete authoring language Shared declarations, expressions, statements, types, and full callable bodies; meaningful edits and readable diagnostics on the adopted corpus. Shared kernel, optional marker, ordinary-action replace successor relations, and the focused schema-acknowledgement workflow are implemented; remaining relation forms, graph-wide upgrade integration and corpus evaluation are pending.
No 2026 feature regression Positive and negative cross-edition source, typed obligation, format, artifact, and runtime checks for the feature families below. Dedicated differential and syntax-combination tests preserve the admitted cross-edition boundary. The bounded 0.30 candidate 74cff5fd passed dev, full ci within release, backend, and release; broader authoring extensions still need their own regression evidence.
Direct semantic elaboration Structured relation nodes with spans, typed schema resolution, and checked lowering; no generated preview4 text reparsing. Implemented for replace: parser, AST, type checking and IR elaborate the relation directly, including concrete-schema same except; other constructor forms remain pending.
Path-sensitive successor relations Assigned/preserved fields, identity, lock, capacity and output correspondence compose inside ordinary if/match; every accepting path accounts for roles. Implemented for authoring relations: source-level completeness (conditional skip, double disposal and loop disposal rejected) and relations in each branch of an if compile and validate after sibling arms stopped reusing non-dominating schema-field materializations.
same except and upgrades Concrete schema identity, exhaustive expansion, reproducible focused acknowledgement, changed/stale/missing acknowledgement rejection, no implicit repin. data = same except expands against the resolved concrete schema. cellc schema-ack now emits a hash-bound plan, blocks implicit preservation of added fields, creates a named-review receipt only after explicit assignment, and rejects changed/tampered/stale receipts without mutating package or deployment state. Issue #20 still owns graph-wide upgrade-plan consumption.
Constructor defaults A1-A6 policies are total under resolved context; lock omission, capacity alternatives, identity, group coverage, alias rejection and pool domains have one checked meaning. Relations require explicit data, lock, capacity and identity treatments (omission is rejected, not defaulted); lock = exact(address), lock = exact_hash(script_hash), and lock = same are executable with checked conservation. exact_hash requires the dedicated ScriptHash domain; other constructors remain pending.
Exact artifact entry Codegen, semantic metadata, CLI execution and explicit entry scoping agree, including selected actions calling other retained actions. Shared selection, terminal scalar/Unit helper failure and VM regressions implemented; policy Cell-bearing and complex-ABI callee closure remains pending.
Resolved physical bindings One typed per-binding source/ordinal/identity plan drives codegen, provenance, roles and independent checks; mixed Cell/read/witness/Script.args layouts cannot disagree. Fixed-Cell runtime plan and typed projection checks implemented; full ABI and machine-dataflow closure remain pending.
One deployed multi-action policy Declared action set and explicit versioned dispatch bind selectors, payloads, common checks, artifact identity and builders. Bounded fixed-role Type policy implemented in compiler/VM, metadata/expansion and package/builders; full consumer and deployment closure remains pending.
Dispatch rejection Reject unknown/duplicate/ambiguous tags, wrong versions, malformed/oversized/trailing payload, branch confusion and missing policy checks. Focused real VM negatives cover the bounded envelope and all four fixed cardinalities. Lowering record v8 independently binds its canonical scanner, one selected Type/current-Script-hash record, declared tag targets, ordered common-check dominance, argument forwarding, exact adapters and fail-closed completion to machine instructions.
Lock authorization Actual transaction-bound credential proof; reject copied owner values, missing/invalid proof and signed-transaction tampering. The frozen authorization matrix is accepted: real multisig and issuer-bound persistent-policy fixtures reject copied-owner, wrong-domain/key, partial-signature, and post-signing tampering. Typed Script identity and exact standard Lock/external-verifier boundaries are defined in the cryptographic matrix. Local node acceptance and the selected twelve-artifact Pudge deployment are separately recorded; they do not imply deployment of every policy fixture.
Script identity API Distinguish address decoding, full Script construction/hash comparison and signature verification; wrong-domain values fail typing or checked conversion. Implemented for the frozen 0.30 portfolio: typed transaction views expose complete hashes as ScriptHash; ckb::script_hash(Hash) is an explicit domain conversion; script::args, script::new, and script::hash construct and hash a canonical complete Script with at most 459 args bytes; authoring exact_hash rejects Address and raw Hash; fixed ExactScriptHandle values bind an admitted artifact/deployment receipt to a selected full Lock/Type Script hash or verifier CellDep data hash; the deployment-line foundation hash-links Type-hash exact versions under derived six-dimensional compatibility and active/yanked policy; ckb-type-hash keeps generated Type-hash artifacts in a distinct checked profile; standard TYPE_ID admission/code Cell evidence, exact admission transitions, and node-backed pre-signing resolution bind ProtocolBundle use; and fixed DeploymentLineHandle helpers enforce the active admission commitment, exact code, and selected Script identity in CKB-VM. Standard multisig uses the pinned system Lock boundary, while BIP340 uses the exact external verifier ABI. Address-string parsing, generic interface-compatible handles, unbounded/dynamic Script args, and unrestricted native signature algorithms remain outside the admitted portfolio. See the 0.30 cryptographic capability matrix.
Orthogonal obligations Compose lifecycle, identity, asset accounting, capacity and authorization without double counting; scope and authenticated external guarantees remain distinct. Executable relation sugar produces the same typed obligation set as its spelled-out 2026 form for data, capacity, identity and exact-lock treatment. Bounded trusted-external EXEC/SPAWN now binds exact CellDep data identity and scoped guarantee claims under a separate evidence tier; broader constructor composition remains pending.
Witness ABI contexts Type input/output-only entries, Lock entries and shared witnesses have bounded, non-overlapping ownership; preserve old ABI bytes where compatible. Empty-group fallback, canonical bounded multi-record Type envelope, independent host/adapter codecs and pre-signing placement implemented; full signed shared-policy integration remains pending.
Token lifecycle Execute generated Token Type Script under one persistent policy through authorized mint, transfer, merge and burn, with positive/negative VM and chain evidence. Real CKB-VM coverage executes the complete issuer-authorized lifecycle under identical policy bytes, using earlier verified outputs as later inputs, across both editions and optimization levels 0-3. The accepted release evidence separately binds the strict bundled token artifact to local node admission and Pudge deployment. That selected deployment is not evidence that this distinct persistent-policy fixture has itself been deployed.
Schema-change lifecycle Add approval_nonce, require reviewed reset on transfer, reject unchanged preservation and stale acknowledgement; retain old deployed-byte meaning. Implemented for one explicitly selected local concrete same except relation: unchanged implicit preservation yields SACK1001; approval_nonce = 0 is production-executable and receipt-eligible; tampered or changed relation receipts reject. Every schema delta remains marked as requiring a separate state migration, and issue #20 integration is pending.
Remaining business corpus Exact per-row fixtures for the frozen NFT/DOB, fungible, committed-state, temporal, authorization, multi-Script, external-verifier, and order/AMM scenarios. All eight frozen families now have exact per-row artifact and transaction fixtures. Order/AMM closes its last four rows with the matched pool-merge artifact, live-set replay rejection, and a focused AMM artifact for price and output-order enforcement. Reference reproduction, selected-network evidence, and independent review remain separate release requirements.
Independent artifact checking Version and validate any new records, recompute identities, bind selected entries/relations/dispatch to machine evidence, and add adversarial mutations. Typed policy, declaration/ABI and builder parameter projection checks implemented. Trusted-external records are independently bound to an ordered same-CellDep hash-check/delegation sequence with mutation negatives. Lowering record v8 binds the five typed HeaderDep reads, canonical constructed-Script hashing, and the bounded policy selector/adapter path to exact machine sequences. Rebound mutations cover every policy stage; arbitrary callee semantics and deployment authentication remain separate evidence.
Language services and products Parser, recovering diagnostics, formatter, LSP, editor, native CLI, WASM, package loading, public interfaces and builders agree. The accepted bounded 0.30 surface has compiler, formatter, LSP, editor, builder, Registry, and browser metadata parity at candidate 74cff5fd. Its canonical WASM is 571,696 bytes gzip; VSIX and website builds pass. Product gitlinks were pushed on 2026-09-19. Public publication remains open under #27, and broader authoring constructs require separate consumer work.
Reproducibility and compatibility Source/cache/profile versions, package locks, mixed editions, interfaces and deployment changes are explicit and reproducible. Source/cache identity advanced; later ABI/dispatch/schema migration pending.
Production acceptance Applicable dev, ci, backend and clean-source release evidence, exact artifacts, runtime negatives, cycle/size/capacity measurements and required independent review. Candidate 74cff5fd passed dev, full ci within release, backend, and release, including fresh pinned CKB production/stateful acceptance. Exact deployment-byte reproduction covers the twelve selected Pudge artifacts. Independent review was explicitly waived by the maintainer, not performed or passed. These results apply to the frozen 0.30 portfolio, not every broader authoring requirement.

The target includes all A1-A6 contracts, all acceptance fixtures in the authoring target, and the applicable RFC gates. This checklist does not remove their requirements or turn an experimental source identity into a release identity. Public publication or a mainnet deployment is not implied by local acceptance.

Edition 2026 parity inventory

The authoritative baseline is the current Edition 2026 implementation and its positive/negative evidence, not an older minimal tutorial. Preserve existing supported behavior and the exact unsupported boundaries. An already unsupported dynamic collection does not become a new parity obligation; a supported bounded 0.26 collection cannot be downgraded to a fixed-role preview.

Feature family Evidence to retain and extend
Modules and interfaces Imports and aliases, qualified names, project resolution, public/package/private visibility, stable interface extraction and compatibility diagnostics.
Declarations Resources, shared Cells, receipts, structs, enums, constants, invariants, flows, helpers, actions and locks; attributes and documentation survive.
Types and generics Scalars, fixed bytes, tuples/arrays, canonical fixed_value normalization, derived aggregate abilities, phantom identity, bounded monomorphization, imported public generic instantiation and unsupported-layout rejection.
Policies Capabilities and entailment, identity and destruction policies, type/hash declarations, capacity floors, validity and effect annotations.
Values and control flow Checked arithmetic, wide integers, bitwise/shifts, casts, calls, assignments, aggregates, nested patterns/guards, branching, loops, labels, early returns and borrow regions.
Entry roles Existing value, witness, input/output, protected, lock-args and read-only sources, rich ABI marshalling and named outputs; provenance is not authorization.
Verification Individual/block require, custom failures, pure/read-only helper calls, flow transitions, terminal evidence, invariants and bounded quantifiers.
Lifecycle Create, consume, destroy, claim, settle, unique creation/replacement and continuity; equivalent new forms must exist before any old supported operation is removed.
Bounded collections Exact GroupInput scanning, fixed-width decoding, zero/one/N/N+1, checked accumulation, output-plan codec and complete output correspondence, including negative cases.
Consumers and evidence Metadata, ProofPlan, scheduler/effects, source maps, checker, CLI/builders, project/lock handling, formatter, LSP, editor and WASM.

tests/authoring_parity.rs provides representative differential and runtime cases. tests/syntax_combo/matrix.toml drives the generated cross-edition combination audit. Neither corpus by itself proves the whole table: imported packages, runtime ABI, deployment and product evidence need their matching integration suites and gates.

Authoring successor relations

The authoring route now accepts replace before -> after { ... } as a statement inside ordinary actions. The declaration is the sole authority for its checks: data { f = same | f = expr } and data = same except { f = expr } resolve against the concrete schema of the bound predecessor (exhaustive coverage, unknown and duplicate fields rejected), capacity = same and identity = same lower to the canonical capacity and type-identity preservation checks. lock = exact(address) binds the successor through the create kernel exactly like std::lifecycle::transfer. lock = exact_hash(script_hash) uses the same machine comparison but accepts only the dedicated ScriptHash source domain. Complete Lock and Type Script hashes read through typed CKB transaction views already inhabit this domain; ckb::script_hash(hash) explicitly treats a trusted raw Hash as a complete Script hash without claiming that the Script exists, is deployed, or provides authorization. An Address or unconverted Hash fails typing.

Elaboration stays at the structured AST/IR level — no preview4 text is generated or reparsed — and tests/authoring_replace.rs holds the relation to the spelled-out Edition 2026 form (identical obligation set, formatter round-trip) plus real CKB-VM positives and negatives for address and complete hash locks. The 2026 grammar keeps replace as an ordinary identifier.

A relation whose successor would need to bind more than the relation states is rejected rather than defaulted. Source-level successor completeness is enforced for the authoring route: a role disposed anywhere must be disposed exactly once on every accepting path, and disposal inside loops is rejected.

lock = same is executable: conservation recognizes the updated-successor shape, where every field is either a verbatim alias of the consumed input or a verifier-checked u64 update whose provenance roots in it (constant offsets keep field provenance, mirroring subtraction). Branch-local relations work in both if arms: cached schema-field reads now carry a branch depth and epoch, and sibling arms or loop bodies re-materialize when the defining context does not dominate, which removes an unsound cross-arm reuse that previously failed the typed-record dataflow check. Existing generated code is unchanged; only the previously invalid branch-local shapes differ.

Binding correctness found during parity work

The comparison exposed existing truthfulness gaps. The fixed-Cell implementation now addresses these rather than copying inaccurate records as reference semantics:

  • Ordinary consume and Cell-backed parameter/output lowering retains transaction Input/Output positions and reports them accurately. Native ports use actual GroupInput/GroupOutput locations with membership and complete fixed-group coverage checks. Nonzero-group VM regressions reject foreign same-layout Cells disguising an invalid active group.
  • Ordinary and native protected Lock parameters use the current Lock group, correcting the implementation against the documented contract. They do not impose a new exact lock-group cardinality requirement. The role guard rejects ambiguous Cells whose Lock and Type hashes both equal the executing Script hash; this is a deliberate acceptance-set tightening, not unchanged behavior.
  • Explicit read parameters use positional CellDep loads. These loads do not implicitly authenticate a deployed Type Script identity. Provenance and role records now classify that membership as unproven.
  • Read parameters and standalone read_ref expressions share one CellDep ordinal allocation. Four-dependency VM cases check each slot and reject the previous parameter/expression alias bypass. Repeated generated names and source aliases do not replace local binding identity.
  • Anonymous creates retain distinct output/local identities and distinct role/disposition records even when generated names repeat.
  • Witness arguments omit runtime-bound parameters from their encoded sequence, and Script.args uses byte offsets. Signature parameter indexes alone do not describe either physical layout. Full shared-layout ABI contracts remain part of production acceptance.

The mandatory fixed-Cell table introduced in typed semantics v5 is retained in cellscript-typed-semantics-v8. The independent checker cross-checks typed locals, roles and provenance, including hash-rebound source/ordinal/identity and missing-record mutations. This does not establish general syscall dataflow equivalence. The source-set artifact cache identity now uses project-source-set-v27-verifier-failure. Fixed membership checks share a demand-driven runtime helper with an explicit 96-byte frame in lowering evidence. This avoids repeating the full hash and role checks in every callable; it does not relax membership or group coverage.

The bounded migration command preserves ordinary Type Script action syntax instead of silently rewriting absolute locations into native group ports. Its existing equivalence checks remain mandatory; graph-wide migration is still outside that command's bounded contract.

These findings are grounded in the compiler binding paths, not a complete security assessment. The implementation must distinguish preserved ordinary 2026 behavior, fixes to inaccurate records, and deliberate new group semantics. Hash equality with an inaccurate record is not a reason to retain the error.

Fatal verification and ordinary helper values

The helper call boundary previously allowed a numeric verification error to return as an ordinary value, which a caller could discard or compare as business data. Generated fatal checks now use a demand-driven current-process EXIT sink. Explicit typed failures end in verifier-failure; ordinary values and deliberate raw statuses keep their existing channels. The artifact boundary specifies the new typed, core-identity and machine records and their limits.

Optimization must preserve an expression unless it is both side-effect-free and proven non-failing. Unused checked arithmetic, casts, indexing, schema reads and transitive failing calls therefore remain evaluations. A bounded constant specialization can still fold proven-total literal helper calls; it cannot substitute a partial callee expression into a differently typed caller context. The optimizer regressions changed from four failing families to 16 passing tests, including existing controls. The lexical-shadowing test is defensive AST coverage: ordinary type checking already rejects duplicate bindings, so it is not evidence of an accepted-source shadowing vulnerability.

Real VM regression work covers both editions and optimization levels 0–3, including discarded/used calls, Unit action chains, imported aliases and malformed dependency reads. That corpus also exposed and now covers fixes for ordinary tuple projection and locally constructed schema-reference ABI failures. Repeated tuple projections, reference aliases, and valid/truncated/trailing external schema forwarding pass in both editions at all four optimization levels. The 11-family ordinary VM suite and three policy helper/common-check families pass; full gates on the final source are still required. These fixes do not complete branch-local successor relations, schema acknowledgements or the complete persistent policy product.

Signing-message boundaries

Authorization integration also exposed a pre-existing unsupported path: env::sighash_all did not construct a canonical transaction digest. It could reach a runtime placeholder returning a zero pointer instead. This is not an implemented signing primitive and cannot be used as an authorization reference.

The shared deferred-call classification now reports ckb-sighash-all-deferred. Production policy rejects it before artifact generation. Audit artifacts terminate the process with runtime error 66 at the call, rather than treating an error integer as a Hash or returning through a helper whose caller could ignore the result. Optimizer call-purity checks retain deferred, unresolved and imported evaluations; argument substitution cannot erase or duplicate an evaluation without the required purity evidence.

The 0.30 branch adds a separate executable contract, env::sighash_all_zero_lock(max_group_inputs, max_inputs, max_extra_witnesses, max_witness_bytes) -> SighashAllDigest. It streams the current input Script-group signing message, replaces the complete first WitnessArgs.lock payload with equal-length zero bytes, and commits to later group witnesses and transaction-level extra witnesses. All four bounds are integer literals and are enforced at runtime. Metadata schema 72 and the standalone checker bind the scope, transform, order, type, and limits to typed semantics and runtime provenance. Differential CKB-VM evidence matches the pinned ckb-sdk-rust generator for this all-zero placeholder domain.

This narrower contract does not implement prefix-preserving multisig message layouts. The legacy env::sighash_all(source) remains deferred, and standard multisig Locks continue to own their message construction and signing flow.

Real VM tests cover direct verifier arguments, discarded and wildcard results, local wrappers, imported aliases and Lock execution in both editions. The existing explicit-message BIP340 and real signed-multisig routes remain distinct supported controls. Browser metadata exposes module-wide scoped fail-closed reasons, and LSP diagnostics include defining helpers as well as actions/locks.

The independent checker rejects reclassification of this known deferred helper after outer-hash rebinding. Its terminal-failure records now independently check the recorded static error assignment and jump to the exact current-process EXIT sink. That does not establish that every deferred call reaches the required failure site: complete call-to-failure machine binding remains an explicit checker completion requirement. The deferred-call behavior has direct VM evidence, separate from the classification and static-site checks.

Bounded persistent Type policy

An explicit package [[artifacts]] declaration selects a concrete resource, numeric action tags, policy-witness-v1 dispatch and ordered common checks. There is no inferred selector, implicit export from source order, or builder choice that can replace a stored Cell's verifier. Package, in-memory and virtual source APIs use the same checked policy resolver; executable and metadata-only paths retain the same selected contract. Explicit builds do not read or overwrite the default entry's artifact cache.

The first implementation has deliberately bounded executable scope:

  • A policy has 1–64 exported Unit actions and at most 16 ordered zero-argument Unit common-check actions. Numeric tags are unique u32 values, including zero and the maximum value; canonical serialization sorts tags numerically. Common-check order is preserved because the first failure is observable.
  • Exactly one concrete Cell-backed schema owns the non-dependency roles. Those roles become current Type-group inputs/outputs with exact dense cardinality, membership, alias and coverage checks. Read-only CellDeps keep their independent ordinals and unproven asset identity. A 0-to-0 variant cannot prove invocation membership and is rejected.
  • Fixed lifecycle operations must account for the same roles on every successful path. Bounded collections, mixed-resource physical roles, Cell-bearing action reuse and complex callee ABIs are not supported by this initial policy path. They remain available through their existing supported ordinary/scoped paths. These restrictions are unfinished feature work, not satisfaction of the Edition 2026 parity requirement.
  • Retained scalar/Unit helpers and actions may perform checked arithmetic, narrowing and require in acyclic bodies. They use terminal verification failure, preserving ordinary results such as 5, 20, 49 and false. Immutable concrete-schema reference parameters remain supported; reference returns remain forbidden by the existing public type-checking contract. Field/index access, physical Cell operations, mutable/wide/aggregate call ABIs and recursive calls remain outside this bounded policy callee contract.
  • Common checks run once before a selected action and may call the same retained bounded graph; unknown generic calls are rejected. Every common check remains a zero-parameter Unit action. A Bool predicate is used by require predicate(...); simply returning false is not an authorization check. Common checks are not exported variants. The independent checker validates their retained call contracts and excludes physical Cell effects, unsupported operations and cycles. Lowering record v8 additionally requires the declared-tag guard, ordered common calls, nonzero-to-done rejection and action dispatch to appear in that exact order in the decoded machine.

The policy ABI uses a bounded canonical Molecule envelope keyed by Script role and complete Script hash. It validates the entire record vector before selection, rejects duplicate or unsorted keys, and leaves each selected action's existing CSARGv1 payload unchanged. The whole WitnessArgs limit is 4,096 bytes with at most eight records. Host and CKB adapter codecs are independently implemented; placement preserves other fields, rejects occupied input_type, and must occur before signing.

Metadata schema 72, cellscript-typed-semantics-v8 and cellscript-semantic-foundation-v3 bind the declared policy, selector provenance, resource layout, variant payload schemas, fixed counts and ordered common checks. Runtime metadata also binds cellscript-ckb-runtime-view-v1, the closed typed CKB view contract used by 0.30 runtime field access. Lowering record v8 retains separate terminal-failure sites and requires the exact new nested versions. The parser-free checker also derives builder encoding flags and parameter order/source/type from the typed record. Its specialized policy check binds the canonical scanner, selector, tag branches, selected argument range and exact action adapters to machine instructions. It does not prove arbitrary action semantics or deployment authentication.

Typed semantics v8 additionally records versioned trusted external verifier dependencies. That record is admissible only when emitted code checks the selected CellDep's exact data hash before EXEC or SPAWN/WAIT. Its separate trusted-external evidence tier binds identity and delegation while explicitly denying any compiler proof of the external verifier's internals; see Trusted External Verifiers.

Focused CKB-VM tests execute mint, transfer, merge and burn against the same compiled policy bytes, including optimization levels 0–3, nonzero group positions, output-only creation, shared witness positions for two complete Script identities, and rejection cases for role/hash/tag/version/length errors, extra or missing group members and failing common checks. These are mechanics fixtures without issuance or ownership authentication. They are not the required authenticated, stateful Token lifecycle acceptance fixture.

tests/policy_authorization.rs separately spends a Token under a real bundled multisig-v2 Lock at a nonzero input position. Transfer and burn reject missing, partial and wrong-key signatures. Post-signing changes to the selector, action memo and sibling record change the actual signing message without changing the raw transaction hash, and fail specifically at the owner Lock. Permitted memo and sibling-record edits succeed after legitimate re-signing. This establishes spending authorization for that witness group, not authorization of arbitrary other groups, issuer-authorized minting or the full required Token lifecycle.

tests/policy_lifecycle.rs separately runs the issuer-authorized Token lifecycle in real CKB-VM: positive Token Cells are always outputs of earlier verified transactions, and every action runs under the identical persistent policy Script. Six committed transactions per edition and optimization level cover authorized mint, transfer, merge and burn, replay rejection, wrong amounts, missing/extra outputs and wrong-key credentials. Its negatives also pin the issuer bound itself: an attacker Cell, an issuer Cell reachable only through CellDeps, and out-of-range issuer indexes must all fail. The last case exposed a generated-code defect now fixed: the runtime SourceView helper added an unchecked dynamic index to the tagged view word, so an index at or above 2^32 carried into the view tag and re-routed an Input request to an Output view, letting an issuer-locked output counterfeit input authority. The helper now fails closed with ckb-source-view-invalid (44) before encoding. This is local live-Cell bookkeeping against the workspace SDK, not node admission, chain confirmation or clean-tag release evidence, and the complete required lifecycle fixture remains pending.

build, check, metadata, expand, gen-builder and entry-witness accept explicit artifact selection. Metadata/expansion use the checked metadata-only path and do not generate an ELF. Builders expose only declared variants. The CLI encodes typed action arguments; generated TypeScript's policy helper takes pre-encoded inner argument bytes and leaves typed materialization, shared-index aggregation, placement and signing to its runtime contract. Native full/metadata transport tests cover scalar, fixed-byte, nested aggregate, schema, enum and Unit payloads. Imported concrete resources and failure-free helpers have file/virtual-source differential coverage in both editions. The Rust WASM-feature path retains bounded policy metadata without serializing native typed/machine evidence; it is not a browser ELF compiler. A public browser policy-selection binding and editor integration remain product work.

The bounded independent machine proof begins at the actual ELF entry and uses decoded control flow and call targets rather than trusting source labels or declared reachability. It binds canonical witness parsing to the selected tag and argument range, numeric tag branches to actual adapter targets, ordered common calls to unchanged nonzero rejection, and adapter pointer/length/private copy plus typed-derived outgoing stack behavior to the selected action. Valid matrices cover both editions, optimization levels 0-3, payload and payload-free actions, no-common-check policies and extreme tags; rebound machine mutations cover every stage. Callee memory effects, parameter decoding inside the action, and predicate semantics remain separate obligations: proving a call dominates dispatch does not prove what that call checks.

Next implementation boundaries

The next vertical slices must share an explicit resolved entry context. They must not infer group ownership from the source edition or from the presence of the retained preview AST annotation.

  • A policy declaration is the sole authority for its exported variants, explicit tags, common checks, group resource and versioned dispatch ABI. Package, in-memory and virtual-source compilation must resolve the same declaration model before producing executable or metadata-only products. Builders must not expose retained helper actions as dispatch variants.
  • Group rebinding applies to the exact resolved policy resource, not every resource-shaped parameter. Read dependencies keep their CellDep locations. Mixed absolute/group lifecycle roles need physical alias and coverage checks; changing every role to GroupInput is not a substitute. Unsupported combinations in the new policy path need explicit diagnostics without removing the existing ordinary/scoped compilation path.
  • Internal calls and entry adapters are distinct. Current action preludes can reload transaction Cells instead of using passed Cell pointers. A retained action must not silently acquire either a public tag or a new binding context. Cell-bearing action reuse needs caller-anchored bindings, not merely disabling one parameter-loading flag.
  • Direct successor nodes must carry individual occurrence identity and their actual CFG position. Every successful path must cover its lifecycle roles; no successful path may dispose of one role twice. Explicit failure exits need not finish a transition. A global union of branch dispositions cannot prove those properties. Field, identity, capacity and authorization obligations remain separate from unique lifecycle accounting.
  • same except expands after concrete schema resolution and instantiation. Every field treatment must be explicit in the resulting semantic record. The v1 schema acknowledgement is separate review evidence bound to the relation and old/new schema identities; a newly added implicitly preserved field blocks receipt creation. Existing preview envelope labels are not a substitute for deriving policies from the actual relation and its checks.
  • The policy witness encoder must preserve existing single-entry CSARGv1 bytes. Introduce a separate bounded, versioned multi-record envelope for overlapping Script groups, with explicit field ownership and rejection of duplicate or unknown selectors. Assemble it before signing; never silently overwrite or merge an occupied signature or argument field.

The signed multisig fixture in tests/entry_witness_abi.rs is a useful existing authorization anchor: it combines a real Lock and generated Type Script at a nonzero input position and rejects witness tampering after signing. It is not yet the shared-policy lifecycle fixture. Its current local SDK dependency is not clean-tag release evidence; release validation must use the required pinned SDK without overwriting unrelated checkout changes.

Local differential-evidence refresh

The fixed-binding runtime and exact-size guard optimization satisfy the existing example size and machine-shape budgets without increasing them. The ensuing backend gate exposed stale measured iCKB snapshots. The supported refresh path reran all 218 ickb_diff tests; each retained its asserted transaction outcome. A recursive comparison of the 187 matrix rows found no added or removed scenario, fixture change, accepted/rejected outcome change, original binary change, or capacity, fee or transaction-size change.

There are 92 changed generated-artifact hashes and eight lower CellScript cycle measurements: two deposit positives each save eight cycles, and six limit-order positives each save 22. Error-URL code hashes and dynamic transaction context hashes also change. Three malformed-deposit negatives require an explicit additional qualification:

  • Nonzero DAO data previously reported the DAO Script at Outputs[0].Type with error -19; it now reports the generated policy at Outputs[1].Type with error 11.
  • Short and long DAO data previously reported the DAO Script with error -4; each now reports the generated policy with error 11.

The pinned ckb-script 1.1.0 verifier iterates Script groups by full Script hash and returns the first failure. The changed generated ELF changes its Script identity and moves its explicit malformed-deposit rejection before the DAO rejection. These are first-reported-error changes, not identical exit-code evidence. The named failure modes and rejection outcomes remain unchanged.

This is a working-tree evidence refresh, not a new production-equivalence claim for the authoring target. The matrix's pre-existing cellscript_source_commit marker still names 0be86497a0c1918a9b11bd74f9ccbf234f6c49fe; the refresh command does not update it or prove current-source reproducibility. The compiler source pin and locally refreshed benchmark submodule must be closed together before release. No benchmark submodule publication is authorized by this refresh.

Terminal-failure snapshot refresh

A second supported refresh after the terminal-failure backend changes passed all 218 tests. Compared with the preceding working-tree matrix, all 187 differential outcomes remain unchanged: 37 accepting and 150 rejecting rows. The 22 supporting evidence rows are unchanged. Fees, capacities and transaction sizes are unchanged. The new matrix SHA-256 is 1d7e3d07797b96fbbfe080981b1fad1a16963f01327e3c9974a0f93c770756bb.

All 37 measured positive transactions use fewer cycles on both sides of the comparison: the CellScript-side reductions range from 238 to 480 cycles, totaling 9,540, and the original-side reductions total 5,310. These are complete transaction measurements, including shared generated auxiliary Scripts, not isolated measurements of either principal verifier. Rejecting rows retain zero cycle placeholders, not measured zero-cycle executions. The matrix does not record ELF byte sizes, so this comparison supplies no iCKB ELF-size delta.

Generated artifact and shared auxiliary hashes change. Four normalized fixtures change only their derived related-Type hashes; the wrong-Type relationships and checked data-rule failures remain intact. Fourteen expected patched Owned-Owner artifacts also change with their embedded related-Type hash. Source pins, pinned original binary inputs, test assertions and failure-mode classifications are unchanged.

One negative changes its first reported failure: the receipt wrong-XUDT-owner case previously reported generated error 48 at Inputs[0].Type, and now reports standard XUDT error -52 at Outputs[0].Type. Recomputed full Script hashes put the unchanged XUDT group between the old and new generated group in the pinned verifier's ordered map. Thus this transaction still rejects, but this row no longer independently executes the later generated failure. A separate receipt-group wrong-XUDT case still reaches generated error 48. This is a qualified diagnostic change, not identical exit-code evidence or a new production-equivalence claim. The earlier source-pin and submodule-publication limitations continue to apply.

Source-view bound snapshot refresh

A third supported refresh after the SourceView index-bound fix passed all 218 tests. All 187 differential rows keep their scenario, normalized fixture, fee, capacity and transaction-size values, and all accepting/rejecting outcomes are unchanged: 37 accepting and 150 rejecting rows. The new matrix SHA-256 is 899eb2844bd940132a3936f17aca264ac7fc57c55599b1e1dbb2eebd74c2725d.

Every generated artifact hash changes because each measured artifact references the hardened SourceView helper. The 37 measured positive transactions use more cycles to execute the added bounds check: increases range from 15 to 83 cycles, totaling 1,926. Rejecting rows keep their zero cycle placeholders. The 150 rejecting rows' diagnostic URLs embed the new Script hashes; error codes and reported sources are otherwise unchanged.

One negative again changes its first reported failure, reversing the earlier qualified direction: the receipt wrong-XUDT-args case previously reported standard XUDT error -52 at Outputs[0].Type, and now reports generated error 48 at Inputs[0].Type. The recomputed full Script hashes reorder the pinned verifier's ordered group map back. The transaction still rejects on both sides with the recorded wrong_xudt_binding failure mode. This is a qualified diagnostic change, not identical exit-code evidence or a new production-equivalence claim. The earlier source-pin and submodule-publication limitations continue to apply.

Acceptance recipe identity closure

The audited transaction recipes (transactions-v0.23.json) still recorded the pre-0.26b artifact identities, so the CKB acceptance live replay aborted at its first artifact_data_hash comparison. Following the established refresh precedent, the rebind closes three distinct CKB identity layers as one audited set:

  • all sixty action/Lock case artifacts and 417 exact code-hash references name the final VM2 output;
  • all 253 Script selectors that reference generated artifacts use Data2, while external dependencies retain their original hash type;
  • 143 embedded full-Script-hash payload occurrences across 30 generated identities are recomputed from the final code hash, Data2 tag and empty args.

The third layer is necessary because the recipes carry complete Script hashes inside witnesses and Cell data as resource identities. Updating an outer code_hash and selector does not update those values. The intermediate replay therefore passed every token.cell action but stopped at nft.cell:create_collection with CellLoadFailed: the transaction selected the new Data2 artifact while its payload still named the old Data1 Script. Recomputing these values from the last full-pass recipe preserves transaction shape and business payloads while changing only the cryptographically derived identity bytes. The clean-source production replay accepts the rebound set and passes all 43 action cases, 17 Lock cases and 26 stateful scenarios / 46 committed steps. Its seven end-to-end lifecycles and 19 action-branch scenarios all commit their valid transactions and retain their required negative rejections.

Compact deployed ELF layout and immediate encoding

The cost audit measured that 50.82% of the audited transfer ELF was zero padding before .text: its payload started at file offset 4,096. The payload now starts at 128, while the LOAD segment still starts at file offset 0 with p_vaddr = 0xff80, p_align = 128, and entry 0x10000. This preserves p_vaddr % p_align = p_offset % p_align and saves 3,968 padding bytes. A shared size/encoding classifier selects single ADDI or representable LUI forms for li, saving another 464 bytes in the audited relation. Its ELF drops from 7,824 to 3,392 bytes; the token-transfer example drops to 2,576. After the complete economic tranche, all 37 recorded positive iCKB transactions remain faster: 805,060 CellScript cycles versus 1,952,526 original-contract cycles in aggregate. These rows include shared auxiliary Script work and are transaction-level measurements, not isolated principal-Script savings. The 0.26 release notes give the byte decomposition, matched Rust scope, and multi-action comparison. The start trampoline keeps its fixed 20-byte ABI shape; the independent checker's exit-site decoder already understood both immediate forms, and its mutation corpus was updated for the new sink layout (corrupting the ECALL itself now trips the instruction allowlist). The subsequent economic tranche shares redundant schema-size checks where dominance permits. Further large stack-offset materialization improvements and compressed 16-bit encodings remain separate backend work; neither is claimed as part of this closure.

Matched cost corpus

tests/cost_corpus.rs compares three named CellScript scenarios against hand-written Rust CKB references with the same checked scope, built under the audited profile (no_std, ckb-std 1.1.0, opt-level z, thin LTO, one codegen unit, aborting panics, llvm-strip). Both sides run on the same VM fixtures and must agree on every accept/reject outcome.

Scenario CellScript stripped Rust ratio cycles CS / Rust
Pool merge (2-in, checked sum, lock binding) 2,512 B 2,816 B 0.89x 6,000 / 9,232
Schema roll (2 fields, one updated) 2,272 B 2,760 B 0.82x 8,661 / 10,350
Ownership-claim Lock 2,232 B 2,304 B 0.97x 5,583 / 6,333

Reading: the original corpus exposed three byte-size counterexamples against tight hand-written references. The complete economic-backend tranche closes all three while preserving the same VM accept/reject fixtures, and also lowers the measured positive cycles. Real system-script deployments for context: DAO 7,896 B, secp256k1 sighash 52,048 B, secp-data 1,048,576 B, xUDT (iCKB original) 33,696 B — different feature scopes, not matched comparisons. The corpus is cost evidence for named samples, not a theorem about arbitrary future programs. The cost regression contract now requires fresh execution reports, independent absolute ceilings, and 18 bounded growth rows; missing measurement tools fail the gate instead of skipping tests. The full mechanisms, Spore/Fiber measurements, and mandatory VM2/Data2 deployment contract are recorded in the 0.26 release notes.

WASM playground bundle budget (historical failure and current closure)

The 0.30 candidate resolves the failure below: the canonical bundle is 571,696 bytes gzip, within the unchanged 600 KB budget, with SHA-256 419e8260c3c6acc9f950adf422de90163533c14af96043ebb7429f935b1393d6. The clean candidate release gate passed with this rebuilt bundle; publication remains withheld under the no-TAC constraint. See the 0.30 issue audit for the candidate and product pins. The following numbers preserve the earlier 0.26b audit, not the current bundle or release status.

At that earlier audit, rebuilding the canonical playground bundle in the pinned container (rust 1.97.1, wasm-bindgen 0.2.121, binaryen 131) after the 0.26b tranches produces a 1,730,601-byte module that gzips to 659,050 bytes (643 KB) — 44,650 bytes over the 600 KB budget that website/scripts/build-wasm.sh enforces, so the script correctly refuses. The committed bundle, last built within budget before these tranches, gzips to 590,700 bytes (576 KB) and was left in place; the over-budget output was not committed. The growth is real surface: the policy, artifact, binding and authoring modules are reachable from the metadata-only compile path and cannot currently be dead-stripped from the wasm build. Binaryen 131 metrics on the rebuilt module attribute it to aggregate compiler code (3,389 functions, ~690K wasm-opt units, ~190 KB of memory data) rather than a single outlier block, so the trim is a feature-gating and surface-reduction work item, not a one-line fix. The ci website check does not rebuild the bundle, which is why this stayed latent. At that point the release gate's check_wasm_release_bundle failed, and resolution belonged to the language-services/product row. The 0.30 closure above fixes that row without changing the budget.

Historical tranche verification and current workflow

The successor-relation tranche passed the complete dev gate on 2026-09-06. That tranche's evidence included all 892 compiler unit tests, the six-case authoring_replace suite, authoring parity, entry selection, both policy suites, the artifact checker and clippy with warnings denied. The registered syntax seed is included in the passing quick matrix: 67 accepted and 56 rejected cases out of 123 generated, with zero failures. The strict quick report is target/cellscript-strict-backend-audit/strict-backend-audit-quick-20260906-162715.json. This is historical development evidence; it does not establish the current WASM, full-backend, chain or release boundaries. Current candidate evidence is recorded in the 0.30 issue audit.

The policy tranche passed the complete dev gate on 2026-09-05. Its strict quick audit report is target/cellscript-strict-backend-audit/strict-backend-audit-quick-20260905-205049.json; the accompanying quick syntax audit accepted 66 and rejected 56 of 122 generated cases, with zero failures. Focused evidence also includes 868 compiler unit tests, native compiler/checker clippy, real policy VM/authorization tests, outer-hash-rebound checker mutations, CLI/builders, imports, native transport parity and the metadata-only WASM-feature test. Generated TypeScript typechecks and all nine generated Node tests pass. These are working-tree development results; ci and clean-source production evidence are separate requirements.

The policy tranche's full backend run also passed compiler, checker and Fiber tests, clippy, both package scenario backends, and the strict audit checks except the final clean-source stateful stage. Its report is target/cellscript-strict-backend-audit/strict-backend-audit-full-20260905-205657.json. That stage stopped before scenario execution because the source tree is dirty. Both policy gate runs predate the terminal-verifier-failure changes; they are not evidence for those newer bytes.

The pre-policy backend run on 2026-09-05 passed compiler tests (including the 218-case iCKB suite), checker/Fiber tests, clippy, both package scenario backends, and the 166-case syntax combination audit. Its final stateful CKB stage rejected the dirty source tree before scenario execution. The report is target/cellscript-strict-backend-audit/strict-backend-audit-full-20260905-202015.json. That is an incomplete backend gate, predates the policy tranche, and cannot be reused as current-source production evidence. Existing user-owned worktree and external SDK changes have not been cleared to bypass the gate.

Focused tests are development feedback. They do not replace the unified gates:

cargo test --locked -p cellscript --test authoring_parity
cargo test --locked -p cellscript --test entry_selection
cargo test --locked -p cellscript --test native_group_binding --test protected_group_binding
cargo test --locked -p cellscript --test read_ref_binding --test resolved_binding_metadata
cargo test --locked -p cellscript --test policy_artifact_checker --test policy_artifact_cli --test policy_imports
cargo test --locked -p cellscript --test policy_authorization --test policy_witness_codec_parity
cargo test --locked -p cellscript-tools syntax_combo::tests
./scripts/cellscript_gate.sh dev
./scripts/cellscript_gate.sh backend
./scripts/cellscript_gate.sh ci

The release gate remains subject to its clean-source, pinned-toolchain, artifact, external-tooling and chain-evidence requirements. Do not weaken a gate or clear unrelated worktree changes to obtain a passing result. Current test outputs and gate reports, rather than this command list, are the evidence.