Repository navigation
Conversation
This was referenced Oct 7, 2026
Peefy
force-pushed
the
pr/wasm-load-package
branch
from
October 7, 2026 12:42
2942d44 to
149be41
Compare
Peefy
force-pushed
the
pr/wasm-load-package
branch
2 times, most recently
from
October 7, 2026 15:33
bbce5b4 to
65ed40f
Compare
Peefy
force-pushed
the
pr/wasm-load-package
branch
3 times, most recently
from
October 8, 2026 03:14
7d51b38 to
c8138bc
Compare
Contributor
Author
Peefy
force-pushed
the
pr/wasm-load-package
branch
from
October 8, 2026 03:27
c8138bc to
3789255
Compare
…l bindings The manifest checked 13 cases across 10 of the 27 dispatchable RPCs, so two thirds of `spec.proto` was untested and the two thirds that were could not disagree with each other about anything the others did. It is now 29 cases across 25 RPCs, generated from a scratch-directory fixture set so the output does not depend on the checkout path. Widen it from 13 cases to 29, and make the expectations protobuf-JSON *default* dialect -- an unset field is absent, not `""`/`0`/`[]`/`null`. That is the one encoding all fifteen runtimes already emit for free; the previous dialect was Python's `always_print_fields_with_no_presence`, which would have forced each of the remaining twelve runners to hand-roll a serializer before it could compare anything. Two things surfaced that are worth more than the new cases: Seven of the eight tracked `kcl-api` pins sat on revisions predating six RPCs added after `FormatTestReport`, so those bindings could not dispatch a third of the spec at all. Both tracked pins (`ruby/Cargo.lock`, `c/Cargo.toml`) are now on `3ec296a9`, and `list_method`/`load_package` pin the fields that a stale core gets wrong, so the next drift fails here instead of passing quietly. Every runner also asserts it covers the whole manifest now. The unported ones (c, cpp, dart, julia, lua, nodejs, swift, wasm, zig) fail that check by design -- it is the list of what Phase 2 has left, and it is why they were not already known to be short. Signed-off-by: Peefy <xpf6677@163.com>
The java runner had 13 of the manifest's 29 cases and no coverage check, so it reported green while executing a third of the spec. Add the 16 missing cases and an `@AfterClass` guard that fails when `cases.json` grows a case this runner does not dispatch. The guard is an `@AfterClass` rather than a `@Test` because JUnit does not order methods: as a test it would fail on a green run whenever it happened to execute before the cases it is checking for. Comparing the schema-mapping documents needed a canonical form -- sorted keys, `filename` dropped -- because `KclType` holds two protobuf maps whose iteration order is undefined, and `filename` is an absolute path. Rebuilding the tree as a `JsonNode` rather than as Java collections keeps a pinned number the same Jackson node type on both sides, so the comparison cannot pass or fail on `1` vs `1.0`. Signed-off-by: Peefy <xpf6677@163.com>
The runner covered 13 of the manifest's 29 cases and had no guard, so it passed while half the spec went unexercised. Dispatch the remaining 16 RPCs and add a coverage check, so a manifest case with no runner is a failure rather than a silent gap. The Zig protobuf runtime has no JSON printer, so the two schema-mapping cases serialise `KclType` by hand in the default dialect the manifest is written in; `renderValue` then sorts keys and drops `filename`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The runner covered 13 of the manifest's 29 cases and had no coverage check, so the other 16 went unexercised. Dispatch them, add the guard, and project `has_error_message` for `validate_code_invalid` alongside the raw diagnostic that cannot be pinned. package:protobuf's `toProto3Json` emits protoc's camelCase names and has no hook for presence, so `_kclType` projects the schema messages by hand in the default dialect the manifest is written in. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The runner covered 13 of the manifest's 29 cases; the other 16 went unexercised with nothing to say so. Dispatch them and extend the coverage check to the whole manifest. Doing so exposed a real decode gap: `LoadPackageResult` fields 11-13 (`imports`, `kcl_mod`, `apps`) were present as structs but had no `SwiftProtobuf.Message` conformance, so they were silently dropped on decode and `load_package` reported no imports, no module name and no apps. Complete the conformances in the file's generated style. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The runner covered 13 of the manifest's 29 cases with nothing to say so. Dispatch the remaining 16 and add a coverage check that fails when a manifest case is never reached or falls through to no handler, which is what a manifest grown by one binding produces in a runner that is not updated with it. That exposed a gap in the bridge: `LoadPackageResult` omitted proto fields 11-13, so the C++ API had no `imports`, `kcl_mod` or `apps` at all and three manifest-pinned expectations were unreachable. Add them; the change is purely additive. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The manifest omits default-valued args, so `GetProperty("format")` threw
for `generate_kcl_json` and `generate_kcl_yaml`. Read it the way the
sibling cases already read `version`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
The manifest omits default-valued args, so `get("format")` returned null
for `generate_kcl_json` and `generate_kcl_yaml`. Read it the way the
sibling cases already read `version`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
The runner covered 13 of the manifest's 29 cases. Dispatch the remaining 16 and add a `[ClassCleanup]` guard that compares the executed set against the manifest's own case list -- a `[TestMethod]` guard would be misreported as a failure on an otherwise green run, since MSTest does not order methods. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The julia runner only drove 13 of the manifest's 29 cases, so a divergence between julia and the other bindings on any of the other 16 would never have surfaced as a failing test. Canonicalise protobuf messages by reflection (dropping proto3 defaults and KclType.filename) rather than hand-writing a renderer per message, and add a coverage guard that compares the dispatch list against the manifest's own case list — the two are written independently, so the check still fails when a case is only covered "in theory". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The runner only dispatched 13 of the manifest's 29 cases and threw at module scope when it met an RPC it had no entry for, so the other 16 were not merely untested — the file could not even be loaded against a manifest that had grown. Replace that throw with a per-case skip plus a coverage guard that names the case and the reason, and compare the executed set against the manifest's own case list rather than against the dispatch table. Three real gaps surfaced while porting, all additive: - FormatPathArgs hardcoded `dry_run: false`, so format_path_dry_run was unreachable. Accept it as an optional argument. - GetSchemaTypeMappingArgs had no k_code_list, so get_schema_type_mapping could not pin a source-only program. Accept it as an optional `sources`. - LoadPackageResult was missing `imports`, `kcl_mod` and `apps`, three of the nine fields the manifest pins. KclType recurses through plain message fields, which a napi object cannot express, so the schema mappings ship as canonical protobuf JSON in a new `schemaTypeMappingJson` alongside the existing name-only summary rather than replacing it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The kotlin runner drove 13 of the manifest's 29 cases, so kotlin could diverge from java on any of the other 16 without a test failing. Add the 16 cases as individual @test methods, mirroring java's scratch-copy, path-resolution and pinned-fields-only machinery, and add an @afterall guard that subtracts the executed set from the manifest's own case list. The new cases need `com.google.protobuf.util.JsonFormat` to render the schema type mappings in the default dialect, so take protobuf-java-util at test scope — protobuf-kotlin does not pull it in, and the published kotlin API does not need it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The lua runner dispatched 13 of the manifest's 29 cases, and its coverage check verified only that the 13 names it already listed existed in the manifest — a check that passes by construction. That is how the manifest grew from 13 to 29 cases while this file kept running 13. Dispatch all 29, and replace the vacuous check with one that walks the manifest's own case list and subtracts the names the runner declares. While porting, three things needed fixing to reach the other 16: - validate_code_invalid compared a bool against the raw err_message string. The diagnostic itself is unpinnable — ANSI escapes plus a random temp path — so the projection now reports success and whether a message is present. - scratch: paths were resolved without copying, so override_file and friends would have written into the repository. Copying goes through lfs rather than penlight, which has no copytree. - exec_args ignored work_dir and did not absolutise k_filename_list, matching the java/python/go runners instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
The wider 29-case manifest exposed three decoder bugs: top-level map entry decoders closed the sink back to depth -1, emitting malformed JSON for any 2+ entry map; Scope.parent/owner and Symbol.owner/def drove kind callbacks into never-begun scratch sinks, hard-failing whenever the core sends them (LoadPackage resolve_ast=true); and the KclType required string array never emitted commas. Expose the two helpers the runner needs, and extend KclLoadPackageResult with has_kcl_mod, the kcl.mod package name, and the apps/imports counts. Signed-off-by: Peefy <xpf6677@163.com>
Port the C runner to all 29 manifest cases like the sibling bindings: per-case scratch copies of the template fixtures, a canonical-JSON printer (sorted keys, filename dropped, integral numbers without .0), generalized tree comparison, the 16 missing RPC branches, and the DISPATCHED_CASES guard that fails the run when the manifest grows a case this runner does not handle. The generate_openapi example matches the qualified AppConfig key the pinned core emits. Signed-off-by: Peefy <xpf6677@163.com>
Signed-off-by: Peefy <xpf6677@163.com>
Signed-off-by: Peefy <xpf6677@163.com>
The core reports .\\__main__.k-style paths on Windows; the manifest pins basenames like the go runner, so split on both separators. Signed-off-by: Peefy <xpf6677@163.com>
The zig-test CI legs crashed the four scratch: cases (lint_path_with_errors,
override_file, load_settings_files, update_dependencies_no_deps) with
'programmer bug caused syscall error: BADF' inside std.Io.Threaded.dirReadLinux,
while local darwin-arm64 runs passed.
Two independent defects, both in zig/src/consistency_test.zig:
* The scratch machinery iterated directories it had opened with the default
OpenOptions (iterate: false). On Linux, std.Io.Dir.openDir maps that to an
O_PATH fd, which lseek/getdents64 refuse with EBADF, so the first directory
read panicked. macOS has no O_PATH, so the same illegal iterate-on-a-
non-iterable-dir passed locally - which is why the failure only showed on
CI. Open every iterated directory (.iterate = true).
* The runner shared mutable state across the test runner's thread pool:
load() lazily initialised the global cache arena unsynchronized (racing
allocations and a double listMethod FFI probe), scratch_seq was a racy
global whose range-based cleanup could delete another test's live fixture
copy, and runCase built request messages from the cache arena, which is not
thread-safe. Serialize load() with a spinlock, namespace scratch
directories per thread (scratch-{tid}-{n}) so cleanup only ever touches the
caller's own directories, and give each case a per-test request arena.
Verified locally (macOS, zig 0.16.0): zig fmt --check . clean and 25
consecutive zig build test runs green, 301/301 tests each.
Signed-off-by: Peefy <xpf6677@163.com>
… consistency The wasip1 artifact only puts fields 1-10 of LoadPackageResult on the wire, but the wrapper decodes all thirteen, so the shape is ready when the core starts emitting them. The consistency runner gains the LoadPackage case and reports the four pinned fields it cannot read rather than comparing them against a core that never sent them, and the two cases that take the process down — Test's panic=abort on an unsupported wasip1 syscall, and GetSchemaTypeMappingUnderPath's non-terminating walk — are probed or skipped deliberately, and said so in the README. Signed-off-by: Peefy <xpf6677@163.com>
Peefy
force-pushed
the
pr/wasm-load-package
branch
from
October 8, 2026 03:46
3789255 to
a0aa2d4
Compare
Three artifact behaviors shape the port: - The test runner (KclService.Test) never returns in the sandbox, and a pending wasmer call never settles, so the limit is declared statically instead of probed on a throwaway instance - the probe hung the suite. - The wasm32 loader qualifies every schema name whenever the sandbox holds more than one .k file, so each case now runs on a fresh instance seeded with only its own fixtures; the shared instance also OOMed mid-suite once the core's allocations accumulated (panic=abort). - LoadPackage emits kcl_mod but the sandboxed manifest parse leaves the package section empty, so those fields are reported, not asserted. Also restores the WASM_DIVERGENT skips the merge dropped (GenerateProto duplicates referenced schemas; GenerateDoc titles its section differently) and corrects the WASI-limitations notes the v0.13.1 artifact made stale. Signed-off-by: Peefy <xpf6677@163.com>
`check_ast_field_types.rb` answers "is every field read with the right decoder?" and cannot answer "how do I build a node?" — a DTO whose fields are all required is mechanically correct and ergonomically useless, which is what kotlin's `AstBuild.kt` exists to stop. Per node struct, a binding now has to offer a constructor, reach every field of the struct through it by name, and not invent parameters `ast.rs` does not declare. A struct is judged once over the union of its constructors, because "can I build a full NumberLit?" is not "can this one overload?". The rules are language-independent and live in `compare`; a collector only answers which struct a constructor builds and what its parameters are called, so a binding cannot end up held to a laxer standard by accident. Kotlin is the first collector. A collector that stops matching reports success, which is worse than useless, so the report prints how many constructors it actually compared, refuses to call zero "ok", and lists the structs it never reached. `test_check_ast_constructors.rb` re-introduces five bugs that actually happened against AstBuild.kt and asserts the rules name the right struct. Against kotlin this already reports seven node types no constructor reaches: Argument, ExternalPkg, IntLiteralType, OverrideSpec, Program, SerializeProgram, SymbolSelectorSpec. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Peefy <xpf6677@163.com>
…dged it
The checker reported seven node types kotlin had no constructor for. Five
of them were the checker's fault, not the binding's: `Argument`,
`ExternalPkg`, `OverrideSpec` and `SymbolSelectorSpec` are fields of
nothing in ast.rs — they are the exec API's `--override-key=value` pairs,
the runner's resolved packages and the parsed forms of `alice.age=10` and
`pkg:a.b`, declared beside the nodes but never reachable from one. `Program`
looked like the root of the tree and is not: it derives only `Debug, Clone,
Default`, holds `Arc<RwLock<Module>>` maps with no JSON spelling, and
`parse_program` sends `SerializeProgram` instead. Demanding a constructor
for any of those was asking for a document no binding can receive, so they
are now excluded by name with the reason written next to them.
`SerializeProgram` is the real gap, so kotlin gets `program(...)` — and it
is reported under the name ast.rs uses, not the one the binding does.
`pkgs` is defaulted because Rust writes `{}` for an empty map just as it
writes `[]` for an empty list, which is what rule 1 now checks as well.
`IntLiteralType` is covered but not visibly: `literalIntType` returns the
`LiteralType` wrapper, because `{"type":"Int","value":{…}}` is what the
tree holds, and the payload is filled in inside. That is a claim no
signature can carry, so it is registered by name and dropping the entry
lets the struct fall back into the unreachable list.
kotlin is clean at 51 constructors. 123 tests pass, including one that
pins `program()` against the document `toProgramJson` writes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
`NOT_NODES` was inert. `Pos` and `AstIndex` are tuple structs, `Node<T>`
and `Spanned<T>` are generic, and the scanner needed a bare name followed
by `{`, so none of the four were ever in `STRUCTS` and the table removed
nothing. Its comment claimed `Spanned` was a blanket trait; it is a struct.
So the parser now reads all three spellings — braced, tuple and unit —
which puts 60 structs in `STRUCTS` where there were 56. `NODE_TYPES` is
still 51, so no binding's report changes, and every name in either
exclusion table is now one the checker can actually see. `MissingExpr`
comes from the unit-struct scan instead of a hand-written entry, and the
guard below makes the tables unforgeable.
`STALE_EXCLUSIONS` aborts when an exclusion names a struct `ast.rs` does
not declare. An exclusion that cannot go stale is one somebody has to
justify; this is the guard that makes the README's rule enforceable
rather than advisory.
`NOT_NODES` now also exempts its four from the rules, not just the
coverage list. Python exposes `Node(node=, id=, pos=Pos(...))` — a
complete wrapper, spelling the five position members as the `Pos` class
they already are and re-flattening in `to_dict` — and rule 2 was
reporting four of `Node`'s five members unset, reading Rust's field
layout as an API requirement.
python's collector is verified against interpreter ground truth:
`dataclasses.fields` over the seven generated modules, diffed field by
field — 64 classes, every parameter list and every defaulted set
identical, nothing parsed that isn't there. The five names it does not
report are module-level aliases (`Decorator = CallExpr`,
`KeyValuePair = ConfigEntry`, `IdentifierExpr = Identifier`,
`SchemaConfig = SchemaExpr`, `TargetExpr = Target`), which are the same
dataclass under a second name and so already covered.
python is down one node type: `parse_program` unwraps the
`SerializeProgram` envelope and returns a bare `List[Module]`, so a
caller can read the document but cannot build one. Not closed here — the
AST is generated, so that is a generator change.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
Adds go, java, nodejs, dotnet, swift, zig, julia, dart and lua. Each one
answers the same three questions and is verified against something other
than its own regex — go against `go doc -all`, java against a census of
the POJO package cross-checked through `@JsonProperty`, nodejs by
importing the module and reading `Object.keys` off every loader's output,
dotnet by reflection over the compiled assembly (156/156 exact), swift by
`swiftc -emit-module-interface-path` plus using the compiler's own
"missing argument(s)" diagnostics as the parameter list, zig and julia
against an independently written parser and `fieldnames`/`methods`,
lua by driving all 62 loaders with `{}` and then removing one key at a
time to prove each is read.
Four table entries the reports earned, each with its `ast.rs` line:
go `Type`/`Kind` join `KNOWN_HELPERS`. Go exports both halves of a
serde tag, and 41 of its 73 structs carry `Type string` for
`#[serde(tag = "type")]` on `pub enum Stmt`. Listed per spelling
rather than matched case-insensitively, because case-folding
would also exempt `ID` and `Raw`, which are real field names.
dotnet `rawPath`→`rawpath`, `asName`→`asname`. `ast.rs` is internally
inconsistent here, not dotnet: `CallExpr.keywords` and `SchemaExpr.kwargs`
are one wire field under two spellings, and `ImportStmt.rawpath`
drops the separator its neighbours keep. Swift's `keywords` meaning
`kwargs` for one struct and `keywords` for another is not an
ambiguity, because an exact match is tried before the table.
zig `test_`→`test`, `orelse_`→`orelse` are forced by the language —
both are Zig builtins. `modules`→`pkgs` is a real rename and the
weakest claim in the table; it is written down for that reason.
nodejs/julia/dart `types`→`type_elements`, and `asName`/`as_name`→`asname`.
Rejected a general "squash the underscores" fallback that would have
covered the ImportStmt pair without a table entry: `ast.rs` declares both
`pkg_path` (ast.rs:350) and `pkgpath` (ast.rs:935), so `pkgPath` would join
to whichever the squash reached first.
`valueTag`/`value_tag` joins `KNOWN_HELPERS`. Both dart and julia split
`NumberLit.value: NumberLitValue` into a discriminator and a payload,
where `NumberLitValue` is `Int(i64) | Float(f64)` behind
`#[serde(tag = "type", content = "value")]`. That is the same answer
`tag`/`type`/`kind` already give.
Where the bindings stand: kotlin and java are clean at 51; python, go and
lua are clean bar `SerializeProgram`, which none of them has because all
three unwrap the envelope and return a bare list of modules. nodejs, swift,
zig and julia are the decode-only bindings and fail rule 1 across the board
— a caller spells `[]` for every `Vec`. Those are real API gaps and the
next thing to close.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
Adds the last two collectors. cpp is clean bar `IntLiteralType` and
`SerializeProgram`; c reaches all 51. C ships no constructor functions at
all — the header's public surface is a parser, four frees and six enum
printers — but that is not the same as having no way to build a node, so
the collector reads the members the language's own designated initializer
takes, which is the same argument `check_go` makes about a keyed literal.
Verified against eleven deliberate mutations of a scratch copy, including
the one that catches the obvious bug: `KCL_DECLARE_NODE`'s body ends
`} name##_t`, and `_` is a word character, so a `\bname\b` substitution
silently expands all fourteen wrappers into one struct called `name`.
C raised seven problems, and every one turned out to be a language
constraint rather than drift. Two are derivable, and deriving them is
strictly better than listing them — the base still has to be a real field
of this struct, so `has_op` beside `SchemaAttr.op` (ast.rs:817) is exempt
and `has_colour` is not:
`has_X` + `X` C has no zero value for `Option<T>`, so the presence
flag is a member of its own.
`X_count` + `X` an array carries no length, so `Compare.ops`
(ast.rs:1387) is a pointer and a count.
`DERIVED_TWIN` resolves the base through `PARAM_ALIASES` rather than by
exact name, because C's `main_package_count` is a twin of `main_package`,
which is only a field by way of that table.
The third — splitting `NumberLit.value: NumberLitValue` (ast.rs:1478) into
`int_value` and `float_value`, because C has no sum type — is not
derivable and is `ENUM_ARM_MEMBERS`, keyed by lang and struct so one
node's claim cannot excuse another's. `value_kind` is the discriminator
and joins `KNOWN_HELPERS` beside `valueTag` and `value_tag`.
The self-test gains six exemption cases and a third expectation,
`:silent`, for a struct that must NOT be named. That case was missing and
its absence was a real hole: no test exercised `KNOWN_HELPERS`, so
removing it from rule 3 outright left every self-test green while Kotlin's
9 and Go's 41 helper parameters would have started being reported as
drift. `tag` is exempt and `colour` is not, and pinning both is what
makes the boundary exact.
All six mutations of the join — twin, arm table, arm table keyed by
struct, arm table over-broad, `KNOWN_HELPERS`, `PARAM_ALIASES`, and the
camelCase fallback — are now caught by the suite.
Thirteen bindings registered. Where they stand: kotlin, java and c are
clean at 51; python, go and lua clean bar `SerializeProgram`; cpp clean
bar that and `IntLiteralType`; dotnet and dart have two each; nodejs,
swift, zig and julia are the decode-only bindings and fail rule 1 across
the board, because a caller spells `[]` for every `Vec`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
check_julia reads the @kwdef spelling, rule 1 stops claiming Option<Vec<...>> is always written (serde spells a None as null, so C#'s required paramsTy and julia's params_ty = nothing are both faithful), and a load-bearing NOT_MODELED table records the two deliberate gaps the remaining bindings share — SerializeProgram, which parseProgram unwraps into the module list, and IntLiteralType, which LiteralType models verbatim — with each collector header carrying the argument. Signed-off-by: Peefy <xpf6677@163.com>
Every node struct is Base.@kwdef and every field whose ast.rs counterpart
is a Vec or Option<Vec> carries the empty collection as its default, so a
caller builds ConfigExpr() instead of spelling Node{ConfigEntry}[] at
every level of the tree; the positional constructor is untouched and
test/ast_ctors.jl pins the runtime half (fresh defaults per call,
scalars and required nodes still required).
Signed-off-by: Peefy <xpf6677@163.com>
Signed-off-by: Peefy <xpf6677@163.com>
Signed-off-by: Peefy <xpf6677@163.com>
A member whose ast.rs field is a Vec, Option<Vec>, HashMap or Option<HashMap> is marked ? in index.d.mts: Rust never writes an absent Vec, so a caller with no arguments has nothing to say about args, and requiring the key would make every call site spell the empty collection at every level of the tree — the ceremony AstBuild.kt exists to stop. Loaders still emit the key for a decoded node; this is a statement about what a caller owes the object literal, not about which keys it holds. Nothing else is optional: a NodeRef, a scalar or a tagged-enum wrapper is a child the parser genuinely produces. Signed-off-by: Peefy <xpf6677@163.com>
Every std.ArrayList field whose ast.rs counterpart is a Vec or
Option<Vec> now carries = .empty, the zero-allocation spelling Zig's
ArrayList already has, so a caller builds .{ .pkgpath = "" } instead of
an explicit empty list at every level of the tree. Decode paths are
untouched: parse fills every list from the wire, where Rust always
writes the key.
Signed-off-by: Peefy <xpf6677@163.com>
…DTOs The DTOs were decode-only: public lets with no way to build them. Public initializers now mirror AstBuild.kt's contract — every array and dictionary field defaults to empty, a caller writes ExprStmt() or Target(name:paths:) — and Program's initializer derives mainPackage from pkgs["__main__"] instead of taking both, so the two cannot be built disagreeing. Members that map to a scalar or a required child stay required. Signed-off-by: Peefy <xpf6677@163.com>
check_ast_constructors.rb now runs in CI alongside the field-types and declaration checks, with the self-test that breaks constructors on purpose next to it; without it a collector that silently matches nothing would report ok for every binding. The paths filter also learns the kotlin sources' real directory (src/main/kotlin, not src/main/java). Signed-off-by: Peefy <xpf6677@163.com>
Peefy
force-pushed
the
pr/wasm-load-package
branch
from
October 8, 2026 06:08
a0aa2d4 to
d5ab9be
Compare
Contributor
Author
|
Superseded: the wasm LoadPackage decode + consistency coverage landed with #394; this branch has no unique commits left. |
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.
The wasip1 artifact only puts fields 1-10 of
LoadPackageResulton the wire, but the wrapper decodes all thirteen so the shape is ready when the core starts emitting them. The consistency runner gains the LoadPackage case, reports the four pinned fields it cannot read rather than comparing against a core that never sent them, and handles the two cases that take the process down (Test'spanic=aborton an unsupported wasip1 syscall; GetSchemaTypeMappingUnderPath's non-terminating walk) deliberately — documented in the README.Merge order: #393 → #394 → #395 → #396 → #397.