Skip to content

Add mtlrun --input constructed-stack decoder to close the negative-integer input gap#93

Merged
madmax983 merged 1 commit into
mainfrom
negint-input-fix
Jul 15, 2026
Merged

Add mtlrun --input constructed-stack decoder to close the negative-integer input gap#93
madmax983 merged 1 commit into
mainfrom
negint-input-fix

Conversation

@madmax983

Copy link
Copy Markdown
Owner

Before: the text harness (mtlrun) could only seed inputs by prepending unsigned literals to the program, run against an empty stack. A negative input like -24 lexed as Sub 24 and faulted Underflow before the solution ran; a negative list element like [-5 -2] lexed to a quote whose head is Sub and faulted TypeMismatch. This blocked 8 of 15 sealed tasks in the text harness (PR #91 post-mortem, bench/BASELINE-SEALED.md §7-i, bench/sealed/GAPS.md).

After: mtlrun --input '<spec>' decodes a signed input spec into a constructed initial stack, then runs the (unchanged, unsigned-lexed) program text against it. mtlrun --input '-24' <prog>HALT: 8; mtlrun --input '0 [-5 -5 20 -100]' <prog>HALT: -90. Inputs are data, not program text — only the input decoder accepts signs; the frozen lexer is untouched. Absent --input, behavior is byte-identical to before.

How: new parse_input_stack(&str) -> Result<Vec<Value>, String> in bench/validate/src/lib.rs (whitespace-separated top-level items pushed bottom→top; each item a signed scalar or a bracketed, nestable list; flat int lists build Value::Quote([PushInt..]) byte-identical to the int_list test helper, so the text path and the Rust constructed-stack path agree by construction). bench/validate/src/bin/mtlrun.rs gains --input/--input= wiring over the existing run_program seed path; --engine unchanged. Docs: docs/mtl-quickref.md documents 0 N - for in-program negative constants and --input for negative/list inputs; docs/mtl-quickref-min.md gets one line in its non-frozen wrapper (frozen primitive block byte-identical). Demonstration in the new bench/POSTFIX-NEGINT-INPUT.md (the frozen BASELINE-SEALED.md is untouched).

Scope guardrails: no change to the lexer, primitives, glyphs, interpreter semantics, spec §2.3, or the frozen sealed corpus/manifest — verified by cargo test -p mtl-dataset (manifest_matches_sealed_tasks, sealed_disjoint_from_dev pass).

Verification:

  • 7 of the 8 blocked sealed tasks (the encoding-blocked ones with committed solutions) now execute through the text path and pass every vector, including the previously-faulting negatives. Per-task table in bench/POSTFIX-NEGINT-INPUT.md.
  • The 8th, seal_running_max, is NOT resolved and not fudged: it has no committed solution because its authored candidate is algorithmically wrong (seeds the running max at 0). That is an algorithm bug independent of input encoding and remains the single genuine gap, still pinned by tests/sealed.rs::running_max_candidate_is_algorithmically_wrong.
  • cargo test --workspace: 321 passed / 0 failed (baseline 310 + 11 new decoder unit tests).

Closes #92.


Generated by Claude Code

Before: the mtlrun TEXT harness supplied inputs only by prepending unsigned
literals to the program string, run against an empty stack. Because the frozen
Option-A lexer (spec §2.3) lexes `-` as the Sub primitive, a negative scalar
(`-24`) or a list with negative elements (`[-5 -2 ...]`) faulted before the
solution ran. This blocked 7 sealed tasks that have committed, algorithmically-
correct solutions (they only ran under the Rust-only constructed-stack path).

After: add a harness-level signed input decoder `parse_input_stack` in
bench/validate and wire an `--input <spec>` / `--input=<spec>` flag into mtlrun.
The spec accepts signed scalars, signed lists, and whitespace-separated
top-level items (bottom..top), constructing the initial stack directly — flat
lists decode byte-identically to the `int_list` helper used by
tests/sealed.rs. The program text is still parsed by the frozen unsigned lexer;
only the input value flows through the new decoder. No `--input` => identical
old empty-stack behavior. The lexer, primitives, glyphs, interpreter semantics,
and all frozen sealed artifacts/manifests are unchanged.

All 7 encoding-blocked sealed tasks now execute end-to-end through the fixed
text path and pass every vector (positive and negative). The 8th blocked task
seal_running_max is a genuine algorithmic bug (seed = 0) with no committed
solution and is NOT resolved by this encoding fix; that remains the isolated
gap. Demonstration recorded in bench/POSTFIX-NEGINT-INPUT.md;
bench/BASELINE-SEALED.md remains the frozen baseline.

Docs: mtl-quickref.md documents the `0 N -` in-program idiom and the --input
convention; mtl-quickref-min.md gets one terse wrapper line (frozen primitive
block left byte-identical).

Tests: 11 new decoder unit tests. cargo test --workspace 321 passed / 0 failed
(baseline 310 + 11); contamination gates still pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01ANTmGML7M6khvHFtiASeGG
@madmax983
madmax983 marked this pull request as ready for review July 15, 2026 19:20
@madmax983
madmax983 merged commit f06386e into main Jul 15, 2026
3 checks passed
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.

Expose a constructed-stack --input in the text harness (mtlrun) to close the negative-integer input-encoding gap

2 participants