Phase 1 / Etch / Non-POD resource fields (string, enum) exposed to the interpreter#29
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Milestone M1.0.3 — Non-POD resource fields (
string, enum) exposed to the Etch interpreter. The Option A alignment (formerly the deferred "tranche 7"): resource fields reach spec parity for the two scalar non-POD cases.Brief (source of truth,
Status: CLOSED): briefs/M1.0.3-resource-nonpod-fields.mdScope delivered (staged E1 → E2 → E3, each STOP-reviewed via Claude.ai)
src/etch/persistent.zig, Tier-0-agnostic): refcounted system-allocator heap, 8-byte{refcount, type_id}header,type_id→drop dispatch, immortal sentinel. The keystone M1.0.4 collections reuse unchanged.stringresource fields:FieldKind.string_(resource-only), borrowed-view reads (no incref), write = rule-arena→persistent promotion (read-old → alloc+copy → write-slot → decref-old), immortal-interned defaults (zero alloc ataddResource), teardown decref discipline in the Etch runtime (Tier-0 stays string-agnostic).FieldKind.enum_(POD u32 discriminant = declaration-order index),FieldDesc.enum_type_name_id(internedStringId) so the bridge rebuilds a typedenum_value,.variantdefault / first-variant-when-absent, validator unlock.The flagship
GameStateprogram (string+ enum +int) type-checks with zero diagnostics and mutates end-to-end through the interpreter harness, leak-free.Validation (Étape 4 — all green)
GameStateend-to-end)zig build,zig build test,zig fmt --check,zig build lintgreen;commit-msghook green on every commitStatus: CLOSED, close date setdocs(brief): close M1.0.3registry.zig(FROZEN, C0.5/M0.9) edited additively per the brief's "Files to create or modify";resources.zig(FROZEN) kept string-agnostic.Closing notes
What worked
std-only, Tier-0-agnostic; E2 reused it unchanged (StringSlot+ literal registry slotted straight in). The drop dispatch / openTypeIdset are what M1.0.4 collections register against.string_/enum_live in the shared registry path but are emitted only for.resourceand rejected oncomponent; the guard test pins all four cases.What deviated (tracked in § Accepted deviations)
FieldDesccarries the enum type name as the internedStringId(enum_type_name_id: u32), not a string slice (refines review guard 2, confirmed):enum_value.type_nameIS aStringId, and a borrowed AST slice would dangle post-AST-free while the registry persists.size: usizebefore the spec's 8-byte header soAllocator.freerecovers the length; the spec-visible header is preserved exactly (comptime offset asserts).What to flag in review
registry.zig/resources.zigare FROZEN; the registry edit is additive + brief-listed,resources.ziguntouched.tests/etch_interp/diff_runner.zig(out-of-list) got.string_/.enum_ => unreachablearms — mechanical exhaustiveness, POD-only corpus, no behaviour change.Final measures
zig build testexit 0 debug + ReleaseSafe (791/808, 17 skipped, 0 failed); leak-freedom understd.testing.allocator(+CountingAllocator); no new watchdog site.Residual debt (intentional)
Interpreter(E2/E3) —persistent_literals+ slot-decref indeinit; aStringIdfrom one AST in the world's registry. Correct for the single-program path; a future script hot-reload (world reused across an interpreter swap, stubsrc/runtime/main.zig:297, out of scope) must move ownership to world/resource lifetime — additive at reload wire-up (the enum-id case is a logic bug under multi-AST reload, not a UAF — strictly safer than a slice).string[],[K: V],Set<T>) — deferred; reuse E1's persistent heap + E2'sFieldKind/slot/teardown machinery unchanged.Merge + tag (
v0.10.3-resource-nonpod-fields) are left to Guy after PR review.