Skip to content

Commit 2833fd0

Browse files
committed
Harden bounded lifecycle collection lowering
1 parent 06dadf1 commit 2833fd0

22 files changed

Lines changed: 572 additions & 82 deletions

‎CHANGELOG.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
## Unreleased
44

5+
- Harden bounded lifecycle collections at the production boundary. The typed
6+
IR now retains `consume_each` predicates and the `create_each` output
7+
template and lowers both constructs to an explicit registered fail-closed
8+
call instead of silently replacing the body with `Unit`. Non-production
9+
CKB artifacts reject the entry with stable runtime error 24
10+
(`collection-runtime-unsupported`); `--production` and
11+
`--deny-fail-closed` stop before ASM/ELF generation with E2105 and report the
12+
operation, source origin, missing ProofPlan enforcement, and remediation.
13+
Entry ABI metadata no longer presents either bounded collection as a
14+
supported schema pointer, and ProofPlan no longer fabricates a
15+
runtime-observed cardinality. Runtime Cell selection/decoding and witness
16+
plan/output correspondence remain deliberately unsupported until their
17+
consensus semantics are specified.
18+
519
- Bound local compiler and gate storage without weakening the verified-artifact
620
contract. Incremental build caches now retain at most 32 recent identities
721
per cache root, syntax-combination success runs discard reproducible

‎docs/CELLSCRIPT_COLLECTIONS_SUPPORT_MATRIX.md‎

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ not be collapsed into one generic "collections are supported" claim.
2020
| `HashMap<u64, u64>` | Limited | Limited | No production helper surface | Unsupported/fail-closed for production contracts |
2121
| `HashMap<Hash, Token>` | No | No | No | Unsupported; must fail closed |
2222
| `HashSet<T>` | Limited | Limited | No production helper surface | Unsupported/fail-closed for production contracts |
23-
| Cell-backed resource collections | No executable ownership model | No | No | Unsupported until a linear collection ownership primitive exists |
23+
| `BoundedCellSet<Resource, N>` + `consume_each` | Frontend and metadata only | Explicit fail-closed IR; checked predicates retained | No source scan/decoder | Production-rejected with E2105; non-production artifacts return error 24 |
24+
| `BoundedList<Plan, N>` + `create_each` | Frontend and metadata only | Explicit fail-closed IR; predicates and create template retained | No witness codec/output verifier | Production-rejected with E2105; non-production artifacts return error 24 |
25+
| Generic Cell-backed resource collections | No executable ownership model | No | No | Unsupported |
2426

2527
## Stack-Backed Local Vec Rule
2628

@@ -67,15 +69,36 @@ shape. They must produce one of:
6769
- structured blocker in metadata/constraints
6870
- explicit fail-closed runtime path with a registered runtime error
6971

72+
Every selected consensus-relevant ProofPlan status beginning with `gap:` is a
73+
production blocker, including `gap:runtime-helper-required`,
74+
`gap:builder-evidence-required`, and `gap:metadata-only`. A transaction builder
75+
can supply evidence for construction, but that evidence cannot authorize a
76+
consensus operation the emitted Script does not check.
77+
78+
## Bounded Lifecycle Boundary
79+
80+
The bound `N` is currently a static type and complexity declaration. It is not
81+
evidence that a runtime scan observed at most `N` items. Metadata therefore
82+
records the maximum but leaves actual cardinality unobserved.
83+
84+
Positive `consume_each` execution needs a specified transaction versus
85+
script-group source, a resource Type Script identity, canonical cell-data
86+
decoding, actual-count enforcement, and per-element predicate plus consumption
87+
semantics. Positive `create_each` execution additionally needs a canonical
88+
witness list codec, output ordering and one-to-one plan/output correspondence,
89+
fresh Cell identity, and occupied-capacity rules. Until those contracts exist,
90+
use explicit fixed-arity input/output bindings and ordinary lowered
91+
`require`/`consume`/`create` operations.
92+
7093
## Authoring Guidance
7194

7295
Use dynamic vectors for data that is still a single cell field, such as signer
7396
lists, proposal payload bytes, NFT attributes, or launch distributions.
7497

75-
Do not model ownership of multiple independent linear cells as a generic vector
76-
or map. Use explicit action parameters, named output bindings, and explicit
77-
`consume`/`destroy` operations or compiler-recognized stdlib lifecycle patterns
78-
until the language gains a verifier-backed collection ownership primitive.
98+
Do not deploy ownership of multiple independent linear cells through a generic
99+
vector, map, `BoundedCellSet`, or `BoundedList`. Use explicit fixed-arity action
100+
parameters, named output bindings, and lowered `consume`/`destroy`/`create`
101+
operations until the bounded runtime contract is implemented.
79102

80103
The missing verifier pieces are explicit cell consumption, typed collection
81104
destructuring, and membership proofs tied to Molecule schema manifests. Until

‎docs/CELLSCRIPT_GATE_POLICY.md‎

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -340,17 +340,29 @@ quantifiers. It has a compile-time `1..=64` bound, emits a real resolved
340340
positive/missing-dependency CKB-VM cases. Out point, dep type, and original
341341
DepGroup identity remain manifest/builder evidence.
342342

343-
Bounded Cell collections use the same finite-evidence rule. An action may take
344-
`input cells: BoundedCellSet<T, N>` and discharge its linear ownership exactly
345-
once with `consume_each`. A fixed-width witness plan may use
346-
`witness plans: BoundedList<P, N>` and exactly one `create` template per plan
347-
element through `create_each`. `runtime.collection_instantiations` records the
348-
explicit source, maximum cardinality, runtime-cardinality placeholder, vacuous
349-
zero policy, and ownership. Consume iteration remains
350-
`runtime-helper-required`; create iteration additionally emits
351-
`builder-evidence-required` output-count and capacity obligations. The quick
352-
syntax gate covers missing bounds, duplicate consumption, and
353-
`Vec<Resource>` rejection.
343+
Bounded Cell collections use the same finite-evidence rule, but are not yet an
344+
executable production surface. The ownership checker accepts
345+
`input cells: BoundedCellSet<T, N>` only when its binding is statically
346+
discharged once by `consume_each`. A fixed-width witness plan may describe
347+
`witness plans: BoundedList<P, N>` with exactly one `create` template per plan
348+
element. `runtime.collection_instantiations` records the declared source,
349+
maximum cardinality, vacuous-zero possibility, and ownership; it does not
350+
claim an actual runtime count. ProofPlan records
351+
`actual_scanned_cardinality:not-observed-no-runtime-lowering`.
352+
353+
The IR retains the checked predicates and create template, then emits a
354+
registered fail-closed operation. Non-production CKB artifacts return runtime
355+
error 24 (`collection-runtime-unsupported`). `--production` and
356+
`--deny-fail-closed` reject both operations before ASM/ELF generation with
357+
E2105. The diagnostic names the operation, source origin, missing enforcement,
358+
and remediation. The quick syntax gate continues to cover missing bounds,
359+
duplicate static consumption, and `Vec<Resource>` rejection; CKB-VM coverage
360+
pins the exact-negative runtime boundary.
361+
362+
More generally, production treats every selected consensus-relevant ProofPlan
363+
`gap:*` status as a hard blocker. This includes runtime-helper, builder-evidence,
364+
and metadata-only gaps. Builder output/capacity evidence is construction data,
365+
not a substitute for a verifier check.
354366

355367
Type validity uses one evidence contract across parser, type checking, IR,
356368
metadata, ProofPlan, codegen, formatter, and LSP. A pure field predicate is

‎docs/CELLSCRIPT_LINEAR_OWNERSHIP.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ would require a verifier-backed membership and consumption model. Until that
5151
model exists, such cases must remain compile-time rejected or represented as
5252
structured runtime blockers.
5353

54-
Missing verifier pieces:
54+
Missing executable verifier pieces:
5555

56-
- `consume_each`
56+
- runtime source selection, decoding, and per-element enforcement for
57+
`consume_each`
58+
- canonical witness/output correspondence for `create_each`
5759
- typed collection destructuring
5860
- verifier-backed membership proofs
5961
- schema-level ownership witnesses

‎docs/examples/collections_matrix.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ Recommended authoring rule:
1414
- treat nested dynamic containers as schema/ABI boundary shapes unless
1515
metadata, constraints, and verifier evidence prove a concrete production
1616
helper
17-
- model Cell-backed collections with a source-aware `BoundedCellSet<T, N>`;
18-
`Vec<Cell>` is rejected because it hides transaction source and ownership
17+
- use explicit fixed-arity Cell parameters and lifecycle operations for
18+
deployable ownership; a source-aware `BoundedCellSet<T, N>` is currently an
19+
audit-only contract and production-rejected, while `Vec<Cell>` is rejected
20+
because it hides transaction source and ownership
1921

2022
Current stack-backed local `Vec<T>` support is deliberately bounded compiler
2123
lowering for verifier-local fixed-width values. It is not a production

‎docs/generated/CELLSCRIPT_EXECUTABLE_SURFACE_MATRIX.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,5 @@ Production compilation means `--production` or `--deny-fail-closed`; both stop b
7676
| `ir:cell-metadata-equality` | instruction | complete | accepted | Lock-hash or capacity equality over validated Cell views. | `none` |
7777
| `artifact:create-output-verification` | artifact-policy | shape-gated | accepted only when the shape classifier reports no fail-closed feature | All constructed output fields and output lock must be materializable by the verifier. | `output-verification-incomplete, output-lock-verification-incomplete` |
7878
| `artifact:cell-backed-collection-return` | artifact-policy | reserved | rejected by production policy | Returning a hidden Cell-backed collection has no linear ownership ABI. | `cell-backed-collection-return` |
79+
| `artifact:bounded-consume-each-runtime` | artifact-policy | reserved | rejected by production policy | BoundedCellSet source selection, element decoding, and per-element predicate execution are not yet an executable contract. | `bounded-consume-each-runtime` |
80+
| `artifact:bounded-create-each-runtime` | artifact-policy | reserved | rejected by production policy | BoundedList witness codec, output correspondence, ordering, identity, and capacity enforcement are not yet an executable contract. | `bounded-create-each-runtime` |

‎docs/generated/cellscript-executable-surface.json‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,26 @@
611611
"layer": "artifact-policy",
612612
"production_policy": "rejected by production policy",
613613
"status": "reserved"
614+
},
615+
{
616+
"conditions": "BoundedCellSet source selection, element decoding, and per-element predicate execution are not yet an executable contract.",
617+
"fail_closed_features": [
618+
"bounded-consume-each-runtime"
619+
],
620+
"id": "artifact:bounded-consume-each-runtime",
621+
"layer": "artifact-policy",
622+
"production_policy": "rejected by production policy",
623+
"status": "reserved"
624+
},
625+
{
626+
"conditions": "BoundedList witness codec, output correspondence, ordering, identity, and capacity enforcement are not yet an executable contract.",
627+
"fail_closed_features": [
628+
"bounded-create-each-runtime"
629+
],
630+
"id": "artifact:bounded-create-each-runtime",
631+
"layer": "artifact-policy",
632+
"production_policy": "rejected by production policy",
633+
"status": "reserved"
614634
}
615635
],
616636
"schema": "cellscript-executable-surface-v1"

‎docs/releases/CELLSCRIPT_0_25_RELEASE_NOTES.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,31 @@ remain defense in depth rather than a public feature boundary. An unregistered
7474
IR variant fails compilation, and an unregistered runtime feature fails closed
7575
under every policy.
7676

77+
## Bounded Lifecycle Collections Fail Closed
78+
79+
An audit of `consume_each` and `create_each` found a serious lowering gap: the
80+
frontend and ownership checker accepted the bounded body, but IR replaced it
81+
with `Unit`. A body containing `require false` could therefore compile to an
82+
action that returned success without scanning, consuming, checking, or
83+
creating anything.
84+
85+
0.25 removes that path. The typed IR retains the predicates and create
86+
template and contains an explicit fail-closed call. Metadata reports
87+
`actual_scanned_cardinality:not-observed-no-runtime-lowering`; it does not
88+
claim that a helper ran. The entry ABI marks `BoundedCellSet<T, N>` and
89+
`BoundedList<P, N>` unsupported. A non-production artifact returns stable
90+
runtime error 24 (`collection-runtime-unsupported`) in CKB-VM, while
91+
`--production` and `--deny-fail-closed` return E2105 before writing ASM or ELF.
92+
The diagnostic includes the operation, source origin, missing ProofPlan tier,
93+
and a concrete remediation.
94+
95+
This is a safety boundary, not positive runtime support. The language still
96+
needs a canonical transaction/group selection rule and Type Script identity
97+
for `BoundedCellSet`, plus a witness element codec, output order and
98+
one-to-one correspondence, fresh identity, and capacity rules for
99+
`BoundedList`/`create_each`. Builder evidence is not accepted as a replacement
100+
for those on-chain checks.
101+
77102
## Validation Before Release
78103

79104
The implementation is not release-complete until the generated surface and

‎docs/wiki/Tutorial-03-Resources-and-Cell-Effects.md‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@ validated as a named successor output, or handled by an explicit stdlib
6666
lifecycle pattern. Silent loss is rejected because silent loss would make Cell
6767
movement unclear.
6868

69-
## Finite Batch Movement In 0.22
69+
## Finite Batch Contracts (Metadata-Only Boundary)
7070

71-
Use source-aware bounded collections when one action must account for a finite
72-
set of Cells or witness plans:
71+
Source-aware bounded collections can describe how one action intends to account
72+
for a finite set of Cells or witness plans. In the current CKB executable
73+
profile, the following is auditable metadata, not deployable code:
7374

7475
```cellscript
7576
action batch(
@@ -90,16 +91,20 @@ action batch(
9091
}
9192
```
9293

93-
`BoundedCellSet<T, N>` is input-qualified and linearly owned: every selected
94-
Cell must be discharged by `consume_each`. `BoundedList<T, N>` is fixed-width
95-
and may come from witness/static input; `create_each` records a maximum output
96-
cardinality and capacity-builder obligation. The bound makes review and
97-
ProofPlan complexity finite. It does not prove that a builder supplied the
98-
outputs or enough capacity.
94+
`BoundedCellSet<T, N>` is input-qualified and statically linearly owned: the
95+
binding must be discharged by one `consume_each`. `BoundedList<T, N>` is
96+
fixed-width; `create_each` records a maximum output cardinality and
97+
capacity-builder obligation. The bound makes review and ProofPlan complexity
98+
finite. It does not prove a runtime count, a Cell selection, or that a builder
99+
supplied matching outputs and enough capacity.
99100

100101
Generic `Vec<Resource>` and unbounded iteration remain rejected. Inspect
101-
`runtime.collection_instantiations` and the matching ProofPlan records before
102-
treating a batch path as executable.
102+
`runtime.collection_instantiations` and the matching ProofPlan records for
103+
audit, but do not treat the batch path as executable. Production returns E2105
104+
before codegen; non-production CKB artifacts return runtime error 24. Use
105+
explicit fixed-arity Cell inputs/outputs and ordinary lifecycle operations for
106+
deployable code until source selection, codecs, correspondence, identity, and
107+
capacity rules are implemented.
103108

104109
## Borrowed Read Views
105110

‎docs/wiki/Tutorial-06-Metadata-Verification-and-Production-Gates.md‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,21 @@ contract, not proof that the selected artifact emitted or executed that helper.
218218
`runtime.collection_instantiations` also distinguishes local stack collections
219219
from source-aware bounded Cell collections. For `BoundedCellSet<T, N>`, verify
220220
`source = input`, `ownership = linear-cell-set`, the finite `max_elements`, and
221-
the `consume_each` runtime-helper tier. For `BoundedList<P, N>` driving
221+
the `consume_each` runtime-helper gap. For `BoundedList<P, N>` driving
222222
`create_each`, verify `source = witness`, `output_cardinality_max = N`, and
223223
`capacity_builder_evidence_required = true`. Its ProofPlan evidence is
224224
`builder-evidence-required`; it is not proof that a transaction builder supplied
225-
the matching outputs or sufficient capacity.
225+
the matching outputs or sufficient capacity. Actual cardinality must read
226+
`not-observed-no-runtime-lowering`, not `runtime-recorded`.
227+
228+
Neither form is deployable in the current CKB profile. The IR retains the
229+
checked body for audit and emits a fail-closed operation; CKB-VM returns runtime
230+
error 24. Production compilation stops at E2105 before codegen. Treat any
231+
selected consensus ProofPlan whose `codegen_coverage_status` begins with
232+
`gap:` as a blocker, including runtime-helper, builder-evidence, and
233+
metadata-only records. Until the source/codec/correspondence contract is
234+
implemented, write explicit fixed-arity inputs, outputs, predicates, and
235+
lifecycle operations instead.
226236

227237
The validity record first appeared in schema 55 during the 0.22 line and is
228238
retained by current metadata schema 61 as `types[].validity_predicates`. Review each predicate's

0 commit comments

Comments
 (0)