Skip to content

Bump zwasm v1.8.0 → v1.9.0#3

Merged
chaploud merged 1 commit into
mainfrom
develop/bump-zwasm-v1.9.0
Apr 24, 2026
Merged

Bump zwasm v1.8.0 → v1.9.0#3
chaploud merged 1 commit into
mainfrom
develop/bump-zwasm-v1.9.0

Conversation

@chaploud
Copy link
Copy Markdown
Contributor

Summary

Test plan

  • zig build — clean build green
  • bash test/run_all.sh --quick — 4/4 pass (zig build test, cljw test 83 namespaces, e2e wasm, deps.edn e2e)

@chaploud chaploud merged commit 25a02cc into main Apr 24, 2026
6 checks passed
@chaploud chaploud deleted the develop/bump-zwasm-v1.9.0 branch April 24, 2026 07:51
chaploud added a commit that referenced this pull request May 23, 2026
Root-cause hardening after the 2026-05-23 long-context
investigation (`private/notes/llm_long_context_research.md`, 523
lines). The investigation found this session's symptoms (smell
recognised → push anyway, ROADMAP-blind compliance, etc.) were
not LLM attention decay but **CLAUDE.md's own "進め bias" +
autonomous loop's instruction centrifugation** (~80% combined).
Fix:

1. `.dev/project_facts.md` (new) — user-declared invariants the
   loop must treat as fact even when ROADMAP / ADR text admits
   other readings. F-001 (zwasm v2 unavoidable; carries its own
   JIT + GC), F-002 (finished-form wins; smallest-diff is
   tie-breaker not veto), F-003 (decision-deferral on structural
   plans). Added to CLAUDE.md Step 1a Phase reading list.

2. CLAUDE.md "Stop only when (closed list)" extended from 2 to
   3 conditions. Condition 3 is **smell depth ≥ 3 fires 2× in
   one cycle → ADR-phase mode switch** (not a stop; the loop
   pauses the per-task work, forks a fresh-context subagent to
   draft a root-cause ADR, accepts inline, resumes). This
   catches goal drift the per-cycle sensor is too narrow to see.

3. CLAUDE.md Step 6 + § "ADR-level designs are handled inline"
   + .dev/principle.md depth ≥ 2 branch: **Devil's-advocate
   `general-purpose` subagent with fresh context is mandatory**
   before stamping ADR `Status: Proposed → Accepted`. Brief:
   produce 3 alternative shapes (smallest-diff /
   finished-form-clean / wildcard). Output embedded verbatim
   into ADR's "Alternatives considered". Counters the main
   loop's accumulated momentum by sourcing alternatives from a
   context without it.

4. CLAUDE.md Step 6 commit message shape: every source-bearing
   commit body must carry `Smell-audited: <depth 0-4>:
   <one-line summary>`. The deterministic enforcement
   (PreToolUse hook on git push) lands in the next commit.

Handover refreshed: cold-start reading order grows from 4 to 5
files (project_facts.md inserted as #3); recent-landings block
gains Wave 3 description.

Smell-audited: 1: noted "private/notes/ reference in scripts" smell — local-only research note path baked into hook script + CLAUDE.md; deferred (sufficient for current session, file can be promoted to docs/ja/archive/ if cross-session access is needed; recorded inline only).
chaploud added a commit that referenced this pull request May 23, 2026
Wave 4 of the 2026-05-24 user-direction session. Captures the
four direction confirmations the user gave after reviewing the
struct-imagination research note (cw v0 GC + 45-tag enumeration /
zwasm v1+v2 GC / Clojure JVM 140-class survey):

- F-004 NaN-box second generation = 4 × 16 = 64 slot,
  44-bit pointer (128 TB user space — fits all supported
  platforms). cw v0's slot-sharing (5 types in one delay slot)
  is explicitly rejected. Day-1 plan absorbs newly-imagined
  types: range / map_entry / tagged_literal / string_seq /
  array_seq / sorted_map / sorted_set / persistent_queue +
  wasm funcref / externref (for F-001 zwasm integration).
- F-005 Numeric tower = user-observable JVM-surface compatible
  (Long overflow → BigInt; (/ 1 3) → Ratio; 1.5M → BigDecimal),
  internal Zig-stdlib-affine (std.math.big.int.Managed backing,
  Ratio = (BigInt × BigInt), BigDecimal = (unscaled BigInt, i32
  scale)). All heap-allocated in F-004 Group D.
- F-006 GC = single-generation mark-sweep + free-pool +
  3-layer allocator (cw v0 path inheritance). cw v0 D100
  root-set gaps (5 sources patched late) are pre-enumerated in
  the Phase 5 GC ADR draft. zwasm v2 heap stays separate;
  cw GC allocator injects into zwasm internal bookkeeping
  (avoids cw v0 D110 dual-GC leak). Generational deferred to
  ROADMAP §89.2.
- F-007 Chapter cadence stays dormant. The user explicitly
  does not want it to resume unprompted; AI must not propose,
  draft, or re-activate the cadence on its own. Recorded in
  ADR-0025 revision history.

Threaded through:

- .dev/project_facts.md: F-004 / F-005 / F-006 / F-007 appended
  (with verbatim quotes + "what this changes for the loop" +
  cross-references). File grows from 3 to 7 facts.
- .dev/structure_plan.md (new): anticipated directory tree
  Phase 5-20, marked with ★new / ★split + (D-NNN) for each
  divergence from the as-shipped src/ tree. Built from F-001..
  F-007 + the research note. Each Phase entry owner amends in
  place when actual decisions land.
- .dev/debt.md: D-011 / D-014a / D-027 / D-036 descriptions
  rewritten to embed F-NNN references and concrete shape (so
  the per-Phase debt sweep reads the direction without round-
  tripping to project_facts).
- .dev/ROADMAP.md §9.7 (Phase 5) and §9.18 (Phase 16)
  placeholders gain "Entry facts" lines naming F-NNN to load.
- .dev/decisions/0025_chapter_archive_boundary.md revision
  history records F-007 (user-trigger-only resumption).
- .dev/handover.md cold-start reading order grows from 5 to 6
  files (project_facts + structure_plan inserted as #3 and #5).
- .claude/skills/continue/SKILL.md resume procedure step 2a
  reads project_facts + structure_plan before ROADMAP.

Smell-audited: 0: clean — no source files touched, doc layer only
chaploud added a commit that referenced this pull request May 24, 2026
§9.7 task 5.0 closer. Encodes the survey at
private/notes/phase5-skeleton-audit.md (676 lines, gitignored) as
a tracked decision so §9.7 rows 5.1-5.16 execute against a fixed
activation classification map without re-deriving from the
survey.

Two load-bearing decisions:

  §1 Classification of the 8 Phase-4 skeletons:
       4.13 io_interface           matches FF  (Phase 14, ADR-0015 a2)
       4.17 type_descriptor        restructure (5.11)
       4.18 protocol               restructure (Phase 7, D-040)
       4.19 ObjectHeader           matches FF  (5.3)
       4.20 host/_host_api         matches FF  (Phase 6 host wave)
       4.22 binding_stack          reverted    (6a48e90 — terminal)
       4.23 numeric/big_int        restructure (5.2 + 5.9)
       4.24 lazy_seq               restructure (5.7)
       4.25 dispatch/method_table  matches FF  (Phase 7, D-040)

  §2 Critical-path activations for 5.16 exit smoke:
       5.2 → 5.3 → 5.4-5.6 → 5.7 → 5.8 → 5.9-5.10 → 5.11 → 5.12
       → 5.15 (build_options flip, mechanical after 5.12)
       → 5.16 (exit smoke).
       Parallel-safe: 5.13 (analyzer split), 5.14 (host placeholder
       doc).

Devil's-advocate subagent forked with fresh context per CLAUDE.md
§ "ADR-level designs are handled inline" / principle.md
"Devil's-advocate subagent is mandatory at depth ≥ 2". Subagent
output reflected verbatim into Alternatives considered (Alt 1
smallest-diff / Alt 2 finished-form-clean split / Alt 3 wildcard
pattern-ADR). Subagent recommendation: Alt 1.

Main loop disposition: Alt 1 applied with §3 reduced to a
pointer (not deleted entirely — the link to the survey's "5.1
input bullets" stays so future readers find them without
re-discovering); §4 removed entirely per the subagent's
accurate F-003-overlap observation; subagent's omitted-
constraints #1 (per-row OrbStack gate) and #2 (5.15 in critical
path) reflected into §2. Omitted-constraint #3 moot now that §3
is a pointer.

ROADMAP §9.7 row 5.0 flipped to [x] in-place with the survey
SHA / row count + the Alt 1 disposition recorded so future
audits can reconstruct the deferral choice from the row text.

Smell-audited: 1: Devil's-advocate alternative Alt 1 applied
(structural ADR shrink — depth-2 amendment of the draft before
Accepted). The original draft carried the 8 constraint bullets
verbatim; the subagent surfaced the duplication-with-5.1
concern accurately and proposed three alternatives within the
F-NNN envelope. None violated F-001..F-008. F-003 (decision-
deferral) is the active constraint here: ADR-0026 should not
pre-commit decisions the survey only surfaces — 5.1's ADR-0027
/ ADR-0028 cluster owns the bullets at the moment they bind.
chaploud added a commit that referenced this pull request May 30, 2026
…er verb

D-162 finished-form decision. eval is a Layer-2 primitive; the only
missing reach is the built-in macro_table (a process constant; user
macros resolve via env Vars). Adopt Alt 2 (DA-recommended): a typed
driver.evalValue verb (valueToForm→analyze→evalForm) consumed by the
eval primitive with zero casts; the table reaches the driver via one
documented ?*const anyopaque Runtime field set in the setupCorePrefix
funnel (same concession as evalChunk, confined behind the typed verb).
Rejected Alt 1 (per-primitive anyopaque cast — Smallest-diff-bias that
compounds across structural-class-#3 recurrences) and Alt 3 (process
singleton — needs forbidden module-level var per §13). DA output
embedded verbatim in Alternatives considered.

Smell-audited: 2: ADR-level structural choice (precedent for class #3
"primitive needs setup-time resource"); DA fork mandatory at depth 2,
output embedded; picked finished-form-clean Alt 2 over smaller Alt 1
per F-002 (cycle size not a constraint).
chaploud added a commit that referenced this pull request May 30, 2026
…(D-162)

Discharges D-162 per ADR-0058. eval was absent because a runtime
primitive could not reach the built-in macro_table (a setup-time param,
not on rt/env). Finished form (DA-recommended Alt 2):

- Runtime.macro_table: ?*const anyopaque — a documented BORROW of the
  Layer-1 macro_dispatch.Table, type-erased per the zone barrier (same
  concession as VTable.evalChunk), set once in the setupCorePrefix
  funnel after registerInto. Process-constant table; user macros resolve
  via env Vars and need no table.
- driver.evalValue(rt, env, locals, arena, value, loc) — a typed Layer-1
  verb (valueToForm → analyze(table) → evalForm) that casts the erased
  pointer back at the ONE site. Reusable by future load-string / REPL
  read+eval (structural-defect class #3 precedent).
- eval primitive (Layer 2 core.zig) calls evalValue with zero casts;
  per-call arena off rt.gpa holds the transient Form+Node, result Value
  is GC-allocated and survives.

10 e2e (phase14_eval.sh): read-string round-trip, self-eval literals,
constructed lists, special forms, built-in macros (when/->/and expand
inside eval — the structural proof), nested eval. Gate 169/169.
Fidelity limit (follow-up): char/bignum/hash_map literals raise
macro_return_not_data until valueToForm is extended.

Smell-audited: 2: ADR-0058 landed first with DA fork; picked finished-
form-clean Alt 2 (typed verb) over smaller Alt 1 (per-primitive cast)
per F-002 — cycle size is not a constraint.
chaploud added a commit that referenced this pull request Jun 4, 2026
…090 §2)

Smell-audited: 1: Phase B implementation increment #2 per ADR-0090 §2. Added gc_mutex (std.Io.Mutex) to GcHeap; lock alloc/pin/unpin (gc_heap.zig) + the whole collect() cycle (mark_sweep.zig) via the io_default singleton (the allocator API takes no io arg). Makes allocation thread-safe under F-006 — the foundation the #3 ThreadGcContext root-publication handshake builds on for collection safety. Not reentrant (alloc never calls collect; collect never allocates). Uncontended + runtime-inert today (single-threaded; real threads land at #4 future/pmap), so no observable behaviour change. New concurrency test: 4 threads x 500 allocs through a threaded io serialize race-free (allocations.len == alloc_count == 2000). Full --serial-e2e gate green 247/0; the io_default-default-single-threaded gc tests still pass (uncontended lock). bench staged per source-bearing policy (also absorbs the session's dangling doc-commit gate samples). Stale 'lock deferred to Phase B' docstring updated to describe the landed lock.
chaploud added a commit that referenced this pull request Jun 4, 2026
…locks #3; re-analysis gated (D-244)

Smell-audited: 2: Bad-Smell interrupt surfaced while designing increment #3. root_set.zig roots ns_vars/current_frame/macro_root_slot/permanent_roots but NOT the VM operand stack (vm.zig local Value array) nor tree_walk native-stack intermediates; safe today only because collect() runs at quiescent explicit points (no auto-collect). For Phase B real threads (#4), a mid-eval worker's operand/native-stack Values are un-rooted -> concurrent collect UAF; plus a pushFrame/popFrame read-during-write race during another thread's root walk. So ADR-0090 §2 Alt-2's 'no safepoint needed' is insufficient for mid-eval workers. Recorded as ADR-0090 Revision history + D-244 (the #3 gating design step): re-analyse with a DA-fork (safepoint Alt-1 vs publish-VM-operand-stack-root + forbid-tree_walk-during-collect) BEFORE the handshake code. The §1-2/§5-7 spine + increments #1/#2 are unaffected (the alloc lock is needed by either mechanism).
chaploud added a commit that referenced this pull request Jun 4, 2026
…fepoint + per-frame root publication)

Smell-audited: 2: D-244 (the #3 gating design step) resolved via a Step-0 survey + mandatory DA-fork. Survey: cw v0 has the SAME latent bug (vestigial ThreadRegistry; safepoint never landed) — no working mechanism to re-derive. DECISION = Alternative B: (1) force-VM worker thunks via evalChunkErased (D-196 discharged -> build.zig already .vm, so Q2's tree_walk-default fork is moot); (2) the safe point is the ALLOCATION BOUNDARY not the back-edge (Q1: vector/map/set-literal + rest-list-cons loops hold a fresh accumulator across the next alloc, un-installed -> a back-edge poll misses it; the back-edge poll survives as liveness-only); (3) publication is a per-thread CHAIN of operand-stack frames (eval recurses), not one stack. Q3 frame-pop race closed by STW-at-safepoint. No F-NNN amendment (F-006 envelope is expressive enough; no write barrier). Alt C (arena-isolated data-parallel) rejected for the spine (shared-mutable atom/agent/ref -> F-011 divergence) but kept as a future pure-pmap optimization. DA output reflected verbatim. D-244 status -> DECIDED; impl pending = #3 code.
chaploud added a commit that referenced this pull request Jun 4, 2026
…worker-only register, fold-not-11th-source)

Worked out the #3a implementation design (the delicate GC-root-walker rewire): registry lives IN root_set.zig (a separate gc_thread.zig would cycle via macro_root_slot); ThreadGcContext = {frame_slot, macro_slot} pointers to a worker's TLS; only worker threads register (main reads own TLS directly -> existing single-thread tests stay green, empty registry = current behaviour); FOLD the registry pass into the current_frame/macro_root_slot cursors rather than add an 11th RootSource (the 10-source count is asserted + ADR-0028 §5). #3b (safepoint + per-eval-frame operand-stack publication) couples to #4. Captured as the impl checklist so the most-correctness-critical code proceeds from a complete design.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support explicit cancellation of Wasm execution

1 participant