June 3, 2026
Six essays of language design can easily become an excuse not to implement anything. The fastest way to improve this idea is to build a version crude enough to fail.
The first prototype should be designed to disprove the need for a new language as cheaply as possible. It needs one complete vertical slice, matched conventional baselines, a protected evaluation, and enough ablations to identify which component produced any improvement.
It does not need a universal compiler platform.
The previous posts proposed a semantic language, provider reconciliation, an experiment runtime, structured evidence, and protected evaluation. This post turns that architecture into a falsifiable engineering plan.
The minimum vertical slice implements only what authenticated checkout requires.
The core language gets records, variants, named operations, preconditions, postconditions, capabilities, effects, resources, state updates, typed failures, idempotency metadata, event handlers, scenarios, observations, and assertions.
The domain layer gets minimal HTTP, relational storage, identity, and payment interfaces.
The adapters are deliberately fake at first:
Real Clerk, real Stripe, cloud deployment, Python, WebAssembly, plugin frameworks, and additional domains are not required to answer the first question. Add real sandbox adapters only after the semantic path works locally.
The fake payment provider is not a toy if it can reproduce the obligations under test: idempotent checkout, signed events, delayed delivery, duplicate delivery, decline, and eventual entitlement. It is a controlled instrument.
Any favorable result can be manufactured by giving PromptIR a better runtime, better diagnostics, and task-specific primitives while giving TypeScript a terminal and a test suite.
If PromptIR receives billing.create_checkout with idempotency and a fake provider built in, while the baseline has to discover an SDK from documentation, the result says nothing about syntax. It measures tool allocation.
The benchmark must separate at least five variables:
That requires ablations, not one winner-take-all comparison.
Both language conditions should use the same provider simulators, browser runtime, task intent, model, token budget, and protected evaluator. Restricted TypeScript should be allowed explicit capability wrappers, canonical project rules, and structured annotations. PromptIR must earn the additional cost of parsing and lowering.
Useful ablations include PromptIR with weak diagnostics, restricted TypeScript with full structured diagnostics, both languages without the experiment runtime, and both with it. If the runtime supplies all the gain, keep the runtime.
The three primary conditions are:
Building the conventional baselines first has two advantages. It produces tasks and fixtures before the new language can be tailored to them, and it makes the burden of restricted TypeScript concrete. Perhaps a small ESLint plugin and runtime library already solve the problem.
The baseline implementations should not be intentionally ugly. A serious competitor gets the best design we can give it under its stated constraints.
The first compiler needs:
That is already enough work. The parser should use a conventional generator or hand-written recursive descent. The graph can live in memory and serialize to JSON. The TypeScript backend can prioritize readability over optimization. There is no need for incremental compilation, distributed builds, a general optimizer, or an extension marketplace.
Program := Use* Declaration*
Declaration := TypeDecl
| ResourceDecl
| CapabilityDecl
| OperationDecl
| EventHandler
| ScenarioDecl
OperationDecl := "operation" Name Signature
Requires? Effects? Idempotency?
Ensures? Block
Requires := "requires" "[" Predicate* "]"
Effects := "effects" "[" Effect* "]"
Idempotency := "idempotent_by" Expression
Ensures := "ensures" Predicate
The grammar is intentionally unimpressive. The hypothesis concerns semantics and the probabilistic boundary, not punctuation.
Isolated algorithm problems are the wrong benchmark. The proposed advantage is making obligations consistent across application code, effects, runtime state, and environment bindings.
The first task suite should include:
Include greenfield generation, feature addition, code repair, and environment repair. Each task begins from the same repository state in every condition and ends at the same protected assertions.
Repository-level executable benchmarks such as SWE-bench are a better precedent than docstring completion, but this suite needs controlled external systems and cross-layer invariants. The benchmark should publish task fixtures, evaluator versions, model settings, raw trajectories, and failures.
The primary metric is end-to-end protected-evaluation pass rate. It needs supporting measurements:
Secondary costs matter too: human review time, generated backend size, compiler complexity, adapter cost, and the fraction of diagnostics that support a legal automatic repair.
A language that improves pass rate by two points while requiring a year of adapter work may be a bad result. A runtime that cuts failure-localization time in half across all three conditions may be the real product.
A new language has a cold-start corpus problem. The compiler can help bootstrap, but only if generated examples are filtered by independent checks.
Sources of candidate data include:
This is established compiler-testing territory, not magic synthetic data. QuickCheck popularized generating test cases from executable properties. Csmith generated randomized C programs and used differential testing to find compiler bugs. A PromptIR generator can produce typed programs, lower them, execute scenarios, and retain only artifacts supported by compiler or runtime evidence.
The useful training record is not only a source/target pair:
intent
→ initial program
→ compiler result
→ execution
→ observation
→ hypothesis
→ experiment
→ failed patch
→ successful patch
→ verification evidence
That trajectory teaches how to recover, which is most of what an autonomous programmer does after its first generation fails.
The mutation library should inject faults the system claims to detect:
mutation RemoveDeclaredEffect {
input = valid_operation
select effect from input.observed_effects
transform delete(input.declared_effects, effect)
expect diagnostic {
code = EFFECT_NOT_DECLARED
operation = input.identity
observed_effect = effect
}
}
Each mutation has an expected compile-time diagnostic or protected runtime failure. Mutation testing is useful here because the fault is known. If the system reports success, either the evaluator is weak or the claimed semantic guarantee is false.
Do not retain only successful repairs. Failed patches, rejected hypotheses, and unlocalized faults expose where the feedback protocol is insufficient.
After the Storefront slice works, resist adding more web features. Implement one narrow non-web task.
A spreadsheet repair task is a strong candidate. It stresses file ingestion, uncertain schemas, tabular transformation, formula provenance, rendered verification, and a human projection that is not ordinary source code. A small ML experiment with checkpoints and plots is another option.
The goal is not feature parity. It is to determine whether most of the core and experiment protocol survive. If the second domain needs a different resource model, observation model, and evaluator architecture, "universal core" may be an empty label.
The project should continue only if the results justify its complexity.
Evidence in favor would include materially higher end-to-end success under matched runtime conditions, smaller and more local repairs, fewer hidden effects and cross-layer mismatches, stable diagnostics for synthetic mutations, and substantial core reuse in a second domain.
Evidence against would include:
If syntax loses but diagnostics and runtime win, keep the winning pieces. Do not defend a language as an identity project.
Only after the vertical slice demonstrates value should the project discuss Python lowering, WebAssembly, native code, database plans, accelerator kernels, or specialized distributed runtimes. TypeScript is a bootstrap backend, not a permanent semantic boundary—but it is enough to test the claim.
The series began with a question: what should coding agents compile to? The honest answer remains: we do not know.
If restricted TypeScript plus the same runtime performs just as well, do not build the language. If the semantic target wins, we will know which parts earned their complexity.
Previous: Debugging Software No Human Wrote.