Skip to content

harness: validate actual result shape against declared arity - #236

Merged
lannbot merged 1 commit into
mainfrom
harness-arity-shape
Aug 23, 2026
Merged

harness: validate actual result shape against declared arity#236
lannbot merged 1 commit into
mainfrom
harness-arity-shape

Conversation

@lannbot

@lannbot lannbot commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Fixes #188.

assert_return with an empty expected list never inspected the actual value: two stacked layers discarded it independently — compareValues short-circuited to a vacuous pass when expected was empty, and invoke collapsed the raw return by declared arity, discarding it for arity 0 and casting raw as unknown[] unchecked for 2+.

Changes

  • collapseResultsByArity (new, harness/src/value-mapping.ts): pure collapse+validate of the raw invoke return against the declared arity, per the runtime's convention (resultsToHost, runtime/src/exec/boundary.ts):
    • arity 0 → raw must be undefined
    • arity 1 → raw must not be undefined (a ComponentValue is never undefinedruntime/src/cabi/types.ts). Deliberate deviation from the issue's suggested fix: arrays stay legal at arity 1, because a single list<T>/tuple result IS a JS array — disambiguating that from N results is exactly why computeExportArities exists.
    • arity ≥ 2 → raw must be an array of exactly that length
  • RuntimeExecutor.invoke uses it; a shape mismatch now fails the command loudly.
  • compareValues with empty expected now requires actual === undefined instead of passing vacuously.
  • Error messages use a bigint-safe describe helper (JSON.stringify throws on lifted i64 bigints).
  • New unit suite harness/tests/value_mapping_test.ts (14 tests), including pins for the bigint-safe messages and the arity-1-array non-throw.

The collapse is a pure exported function because the arity-0 spurious-result path cannot be exercised end-to-end — producing one requires a broken runtime.

Gates

  • just conformance — pass (1257 passed, 0 failed, 112 pre-existing xfail; all 88 harness tests green). No latent runtime bug surfaced by the stricter checks.
  • just sched-seeds — pass (seeds 1 and 4242).

assert_return with an empty expected list never inspected the actual
value: compareValues short-circuited to a vacuous pass, and invoke
collapsed the raw return by declared arity, discarding it for arity 0
and casting unchecked for 2+. A spurious result from an arity-0 export
passed silently.

Extract the collapse into collapseResultsByArity (value-mapping.ts),
which validates the observed shape against the declared arity per the
runtime's convention (resultsToHost, runtime/src/exec/boundary.ts):
arity 0 requires undefined, arity 1 requires non-undefined (a
ComponentValue is never undefined; arrays stay legal — a single list<T>
result IS an array, the deliberate deviation from the issue text), and
arity n>=2 requires an array of exactly n. compareValues now rejects a
non-undefined actual when nothing is expected. Error messages use a
bigint-safe describe helper (JSON.stringify throws on lifted i64s).

Unit coverage in harness/tests/value_mapping_test.ts; the arity-0
spurious-result path is untestable end-to-end (it requires a broken
runtime), which is why the collapse is a pure exported function.

Fixes #188
@lannbot
lannbot enabled auto-merge (squash) August 23, 2026 03:20
@lannbot
lannbot merged commit f6f2622 into main Aug 23, 2026
3 checks passed
@lannbot
lannbot deleted the harness-arity-shape branch August 23, 2026 16:51
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.

harness: assert_return with zero expected results never checks the actual value

2 participants