plan: cma-revival.1 cross-model harness corpus revival (refs #68)
Bite-sized plan for spec 0069. Six tasks: complete schema fields across the 13 examples + 4 references (own default, existing borrow preserved); rewrite param_modes_all + spec.md section 4 (own Int / borrow boxed-ADT, value/boxed rule); add loop_sum + new_rawbuf examples; spec_completeness variant coverage + Intrinsic allowlist; regenerate rendered + green render suite; migrate mock_full_run fixture + green harness suite. All verbatim .ail/.ail.json bodies parse-gate verified this session. The gate caught a real language drift the spec had to absorb: borrow over an unboxed value type (Int) is now a borrow-over-value error, so param_modes_all borrows over a boxed ADT instead.
This commit is contained in:
@@ -0,0 +1,394 @@
|
|||||||
|
# cma-revival.1 — Cross-model harness corpus revival — Implementation Plan
|
||||||
|
|
||||||
|
> **Parent spec:** `docs/specs/0069-cma-corpus-revival.md`
|
||||||
|
>
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: use the `implement` skill to
|
||||||
|
> run this plan. Steps use `- [ ]` checkboxes for tracking.
|
||||||
|
|
||||||
|
**Goal:** Bring the schema-dead corpus of the cross-model authoring-form
|
||||||
|
harness (`experiments/2026-05-12-cross-model-authoring/`) up to today's
|
||||||
|
language and get both crates' `cargo test` suites green in mock mode — no
|
||||||
|
live IONOS call.
|
||||||
|
|
||||||
|
**Architecture:** The corpus `.ail.json` files lost validity when the
|
||||||
|
implicit-cutover made `param_modes`/`ret_mode` mandatory. Most files already
|
||||||
|
carry their `param_modes`; the repair completes the missing fields in place
|
||||||
|
(preserving deliberate `borrow` annotations), adds two new author-facing
|
||||||
|
examples (`loop`/`recur`, `new`) plus two `spec.md` sections, removes the
|
||||||
|
deleted `ParamMode::Implicit` from the completeness test while allowlisting
|
||||||
|
the non-authorable `Term::Intrinsic` out, and migrates the mock fixture's
|
||||||
|
embedded programs so the harness score assertions still hold.
|
||||||
|
|
||||||
|
**Tech Stack:** `experiments/2026-05-12-cross-model-authoring/` (render +
|
||||||
|
harness Cargo crates outside the root workspace, built via `--manifest-path`);
|
||||||
|
`ail check`/`ail parse` from `target/debug/ail` as the per-file oracle.
|
||||||
|
|
||||||
|
**Files this plan creates or modifies:**
|
||||||
|
|
||||||
|
- Modify: `experiments/.../master/examples/*.ail.json` (13) — complete schema fields
|
||||||
|
- Modify: `experiments/.../master/tasks/*.reference.ail.json` (4) — complete schema fields
|
||||||
|
- Modify: `experiments/.../master/examples/param_modes_all.ail.json` — rewrite (own/borrow only)
|
||||||
|
- Create: `experiments/.../master/examples/loop_sum.ail.json` — Loop/Recur example
|
||||||
|
- Create: `experiments/.../master/examples/new_rawbuf.ail.json` — New example
|
||||||
|
- Modify: `experiments/.../master/spec.md` — §4 rewrite + two new sections
|
||||||
|
- Modify: `experiments/.../render/tests/spec_completeness.rs` — variant coverage + Intrinsic allowlist
|
||||||
|
- Modify: `experiments/.../rendered/json.md`, `experiments/.../rendered/ail.md` — regenerated
|
||||||
|
- Modify: `experiments/.../harness/tests/fixtures/mock_full_run.json` — migrate embedded programs
|
||||||
|
|
||||||
|
Throughout, `AIL` = `target/debug/ail` (built, mtime 2026-06-02) and
|
||||||
|
`XP` = `experiments/2026-05-12-cross-model-authoring`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Complete schema fields in the 13 examples + 4 reference solutions
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `$XP/master/examples/*.ail.json` (all 13 except `param_modes_all`, which is Task 2)
|
||||||
|
- Modify: `$XP/master/tasks/*.reference.ail.json` (all 4)
|
||||||
|
|
||||||
|
The transformation, applied to every `"type": { "k": "fn", … }` object in
|
||||||
|
each file: **preserve any existing `param_modes` verbatim**, then ensure both
|
||||||
|
mode fields are present:
|
||||||
|
- `param_modes`: if absent, set `[]` for a 0-parameter fn, else one `"own"`
|
||||||
|
per parameter (the natural consume default). If present, leave unchanged.
|
||||||
|
- `ret_mode`: if absent, set `"own"` (`borrow`-return is forbidden by contract
|
||||||
|
0015, so `own` is the only legal value).
|
||||||
|
|
||||||
|
Field placement: `param_modes` directly after `params`, `ret_mode` directly
|
||||||
|
after `ret`, matching the canonical key order in the shipped `examples/`
|
||||||
|
fixtures.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Worked example A — `fn_returns_int.ail.json` (0-param)**
|
||||||
|
|
||||||
|
The `answer` fn's `type` block changes from:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"type": {
|
||||||
|
"k": "fn",
|
||||||
|
"params": [],
|
||||||
|
"ret": { "k": "con", "name": "Int" },
|
||||||
|
"effects": []
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
to:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"type": {
|
||||||
|
"k": "fn",
|
||||||
|
"params": [],
|
||||||
|
"param_modes": [],
|
||||||
|
"ret": { "k": "con", "name": "Int" },
|
||||||
|
"ret_mode": "own",
|
||||||
|
"effects": []
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Worked example B — `data_with_match.ail.json` (existing `borrow`, add `ret_mode`)**
|
||||||
|
|
||||||
|
Both fns already carry `"param_modes": ["borrow"]` over `List`. `List` is a
|
||||||
|
boxed ADT, so `borrow` is legal here — leave it untouched; add `"ret_mode":
|
||||||
|
"own"` directly after each `ret`. Do NOT rewrite `borrow` to `own`. (This is
|
||||||
|
the only legal `borrow` in the corpus; the illegal `(borrow Int)` lived only
|
||||||
|
in `param_modes_all`, handled in Task 2. `borrow` over an unboxed value type
|
||||||
|
is a `borrow-over-value` error — `ail check` in Step 4 catches any such slip.)
|
||||||
|
|
||||||
|
- [ ] **Step 3: Apply the transformation to all remaining corpus files**
|
||||||
|
|
||||||
|
Files needing only `ret_mode` (already have `param_modes`): `data_simple.ail.json`.
|
||||||
|
Files needing `param_modes` + `ret_mode`: `bool_str`, `fn_calls_prelude`,
|
||||||
|
`fn_returns_int`, `fn_with_do_seq`, `fn_with_lambda`, `forall_polymorphic`,
|
||||||
|
`match_literal_pattern`, and the 4 `tasks/*.reference.ail.json`. Files with no
|
||||||
|
fn defs (no change to a fn type, but still verify they load):
|
||||||
|
`class_def`, `floats`, `instance_def`. For each value-taking fn, default each
|
||||||
|
parameter to `"own"`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Verify every file checks green**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```
|
||||||
|
for f in $XP/master/examples/*.ail.json $XP/master/tasks/*.reference.ail.json; do
|
||||||
|
target/debug/ail check "$f" >/dev/null 2>&1 && echo "OK $f" || echo "FAIL $f"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
Expected: every line `OK` (param_modes_all may FAIL here — it is rewritten in
|
||||||
|
Task 2; re-run after Task 2). A `FAIL` on a value-taking fn means a wrong mode
|
||||||
|
guess — flip that parameter `own`↔`borrow` per the check error and re-run.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Rewrite `param_modes_all` and spec.md §4 (Implicit is deleted)
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `$XP/master/examples/param_modes_all.ail.json`
|
||||||
|
- Modify: `$XP/master/spec.md` (§4 "Mode annotations", lines ~134-193)
|
||||||
|
|
||||||
|
**Why not "two Int functions":** the typechecker rejects `(borrow Int)` with
|
||||||
|
`borrow-over-value` — unboxed value types (`Int`/`Bool`/`Float`/`Unit`) are
|
||||||
|
always `own`; `borrow` is legal only over a boxed type (an ADT). So the
|
||||||
|
example carries a small boxed ADT and borrows over *that*. The `.ail` below is
|
||||||
|
verified to parse + check green (parse-gate, 2026-06-02).
|
||||||
|
|
||||||
|
- [ ] **Step 1: Author the rewritten example as `.ail` and canonicalise**
|
||||||
|
|
||||||
|
Write `/tmp/param_modes_all.ail` (module name MUST be `param_modes_all` — the
|
||||||
|
checker enforces module-name = filename):
|
||||||
|
```
|
||||||
|
(module param_modes_all
|
||||||
|
(data List
|
||||||
|
(ctor Nil)
|
||||||
|
(ctor Cons (con Int) (con List)))
|
||||||
|
(fn f_own_value
|
||||||
|
(doc "(own Int) — unboxed value types (Int/Bool/Float/Unit) are always own; borrow over them is a borrow-over-value error.")
|
||||||
|
(type (fn-type (params (own (con Int))) (ret (own (con Int)))))
|
||||||
|
(params x)
|
||||||
|
(body x))
|
||||||
|
(fn f_borrow_boxed
|
||||||
|
(doc "(borrow List) — boxed types may be borrowed; the callee reads without consuming.")
|
||||||
|
(type (fn-type (params (borrow (con List))) (ret (own (con Int)))))
|
||||||
|
(params xs)
|
||||||
|
(body
|
||||||
|
(match xs
|
||||||
|
(case (pat-ctor Nil) 0)
|
||||||
|
(case (pat-ctor Cons h t) (app + 1 (app f_borrow_boxed t)))))))
|
||||||
|
```
|
||||||
|
Run: `target/debug/ail parse /tmp/param_modes_all.ail > $XP/master/examples/param_modes_all.ail.json`
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify it checks green**
|
||||||
|
|
||||||
|
Run: `target/debug/ail check $XP/master/examples/param_modes_all.ail.json`
|
||||||
|
Expected: exit 0. (Canonical output carries `f_own_value` param_modes `["own"]`,
|
||||||
|
`f_borrow_boxed` param_modes `["borrow"]`, both `ret_mode "own"`.)
|
||||||
|
|
||||||
|
- [ ] **Step 3: Rewrite spec.md §4 prose**
|
||||||
|
|
||||||
|
In `$XP/master/spec.md` §4 "Mode annotations", remove every mention of a
|
||||||
|
defaulted/omitted/`implicit` mode. Present the exhaustive rule: every
|
||||||
|
`Type::Fn` parameter carries exactly one of `own` (callee consumes) or
|
||||||
|
`borrow` (callee may not consume); `param_modes` is a list with one entry per
|
||||||
|
parameter; `ret_mode` is always `own`. **State the value/boxed rule:** `own`
|
||||||
|
is mandatory for unboxed value types (`Int`/`Bool`/`Float`/`Unit`) — `borrow`
|
||||||
|
over them is a `borrow-over-value` error; `borrow` is available only for boxed
|
||||||
|
types (ADTs), as the `f_borrow_boxed`/`List` example shows. Leave the
|
||||||
|
`{example: param_modes_all}` marker in place.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Add the two new author-facing examples + spec.md sections
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `$XP/master/examples/loop_sum.ail.json`
|
||||||
|
- Create: `$XP/master/examples/new_rawbuf.ail.json`
|
||||||
|
- Modify: `$XP/master/spec.md` (two new sections)
|
||||||
|
|
||||||
|
The module name in each `.ail` MUST equal its target filename stem
|
||||||
|
(`loop_sum`, `new_rawbuf`) — the checker enforces module-name = filename. Both
|
||||||
|
`.ail` bodies below are verified parse + check green (parse-gate, 2026-06-02).
|
||||||
|
|
||||||
|
- [ ] **Step 1: Author `loop_sum.ail` and canonicalise**
|
||||||
|
|
||||||
|
Write `/tmp/loop_sum.ail`:
|
||||||
|
```
|
||||||
|
(module loop_sum
|
||||||
|
(fn sum_to
|
||||||
|
(type (fn-type (params (own (con Int))) (ret (own (con Int)))))
|
||||||
|
(params n)
|
||||||
|
(body
|
||||||
|
(loop (acc (con Int) 0) (i (con Int) 1)
|
||||||
|
(if (app gt i n)
|
||||||
|
acc
|
||||||
|
(recur (app + acc i) (app + i 1)))))))
|
||||||
|
```
|
||||||
|
Run: `target/debug/ail parse /tmp/loop_sum.ail > $XP/master/examples/loop_sum.ail.json`
|
||||||
|
Then: `target/debug/ail check $XP/master/examples/loop_sum.ail.json`
|
||||||
|
Expected: parse exit 0, check exit 0.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Author `new_rawbuf.ail` and canonicalise**
|
||||||
|
|
||||||
|
Write `/tmp/new_rawbuf.ail`:
|
||||||
|
```
|
||||||
|
(module new_rawbuf
|
||||||
|
(fn main
|
||||||
|
(type (fn-type (params) (ret (own (con Unit))) (effects IO)))
|
||||||
|
(params)
|
||||||
|
(body
|
||||||
|
(let b (new RawBuf (con Int) 3)
|
||||||
|
(app print (app RawBuf.size b))))))
|
||||||
|
```
|
||||||
|
Run: `target/debug/ail parse /tmp/new_rawbuf.ail > $XP/master/examples/new_rawbuf.ail.json`
|
||||||
|
Then: `target/debug/ail check $XP/master/examples/new_rawbuf.ail.json`
|
||||||
|
Expected: parse exit 0, check exit 0.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add two spec.md sections with example markers**
|
||||||
|
|
||||||
|
In `$XP/master/spec.md`, after the existing function/ADT material and before
|
||||||
|
§"The prelude", add two sections:
|
||||||
|
|
||||||
|
- **§ Iteration (`loop` / `recur`)** — prose: a `loop` declares one or more
|
||||||
|
typed binders with initial values; the body re-enters the loop via `recur`
|
||||||
|
with new positional values for those binders, or falls through with a final
|
||||||
|
value; `recur` is valid only in tail position. Add a `{form-only: json}`
|
||||||
|
block, a `{form-only: ail}` block, and the marker `{example: loop_sum}`.
|
||||||
|
- **§ Kernel-extension types (`new`)** — prose: `(new T arg+)` constructs a
|
||||||
|
value of an extension type `T` by calling `T`'s `new` definition; args are
|
||||||
|
types or values per the def's signature. Add a `{form-only: json}` block, a
|
||||||
|
`{form-only: ail}` block, and the marker `{example: new_rawbuf}`.
|
||||||
|
|
||||||
|
Keep `{form-only: …}` token volume roughly balanced across the two cohorts
|
||||||
|
(the `token_balance` test allows ±5%).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Update `spec_completeness.rs` — variant coverage + Intrinsic allowlist
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `$XP/render/tests/spec_completeness.rs`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Update the `VariantTag` enum (:22-64)**
|
||||||
|
|
||||||
|
After ` TermReuseAs,` insert:
|
||||||
|
```rust
|
||||||
|
TermLoop,
|
||||||
|
TermRecur,
|
||||||
|
TermNew,
|
||||||
|
```
|
||||||
|
Remove the line ` ParamModeImplicit,` (in the `// ParamMode` group).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Update `EXPECTED_VARIANTS` (:70-105)**
|
||||||
|
|
||||||
|
After ` VariantTag::TermReuseAs,` insert:
|
||||||
|
```rust
|
||||||
|
VariantTag::TermLoop,
|
||||||
|
VariantTag::TermRecur,
|
||||||
|
VariantTag::TermNew,
|
||||||
|
```
|
||||||
|
Remove the line ` VariantTag::ParamModeImplicit,`. Do NOT add a tag for
|
||||||
|
`Intrinsic` — it is allowlisted out (Step 4).
|
||||||
|
|
||||||
|
- [ ] **Step 3: Remove the `Implicit` arm in `visit_param_mode` (:298-310)**
|
||||||
|
|
||||||
|
Delete:
|
||||||
|
```rust
|
||||||
|
ParamMode::Implicit => {
|
||||||
|
observed.insert(VariantTag::ParamModeImplicit);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The remaining `Own`/`Borrow` arms make the match exhaustive against the current
|
||||||
|
two-variant `ParamMode`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Add the new `visit_term` arms (after the `ReuseAs` arm, :220-224)**
|
||||||
|
|
||||||
|
Immediately before the closing `}` of the `match t` in `visit_term`, add:
|
||||||
|
```rust
|
||||||
|
Term::Loop { binders, body } => {
|
||||||
|
observed.insert(VariantTag::TermLoop);
|
||||||
|
for b in binders {
|
||||||
|
visit_type(&b.ty, observed);
|
||||||
|
visit_term(&b.init, observed);
|
||||||
|
}
|
||||||
|
visit_term(body, observed);
|
||||||
|
}
|
||||||
|
Term::Recur { args } => {
|
||||||
|
observed.insert(VariantTag::TermRecur);
|
||||||
|
for a in args {
|
||||||
|
visit_term(a, observed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Term::New { type_name: _, args } => {
|
||||||
|
observed.insert(VariantTag::TermNew);
|
||||||
|
for a in args {
|
||||||
|
match a {
|
||||||
|
NewArg::Type(t) => visit_type(t, observed),
|
||||||
|
NewArg::Value(v) => visit_term(v, observed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// `Intrinsic` is the compiler-supplied body marker — non-authorable
|
||||||
|
// (absent from the parser's term dispatch; typecheck enforces
|
||||||
|
// kernel-tier-only via IntrinsicOutsideKernelTier). A foreign-author
|
||||||
|
// mini-spec must not show it and no master example can legally
|
||||||
|
// contain it, so it is allowlisted OUT of completeness: no VariantTag,
|
||||||
|
// no EXPECTED entry, a no-op arm here so the match compiles without
|
||||||
|
// claiming coverage.
|
||||||
|
Term::Intrinsic => {}
|
||||||
|
```
|
||||||
|
Add `NewArg` to the `ailang_core::ast::{…}` import line at the top of the file
|
||||||
|
if it is not already imported (the build will name it if missing).
|
||||||
|
|
||||||
|
- [ ] **Step 5: Compile-gate the test crate**
|
||||||
|
|
||||||
|
Run: `cargo test --manifest-path $XP/render/Cargo.toml --no-run`
|
||||||
|
Expected: compiles with 0 errors (the `Implicit` unknown-variant error and the
|
||||||
|
non-exhaustive `visit_term` match are both resolved). If the build names a
|
||||||
|
wrong field (e.g. `LoopBinder.init`), correct it per the compiler message.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 5: Regenerate `rendered/` and green the render suite
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `$XP/rendered/json.md`, `$XP/rendered/ail.md`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Run the renderer**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```
|
||||||
|
cargo run --manifest-path $XP/render/Cargo.toml -- \
|
||||||
|
--master $XP/master --rendered $XP/rendered
|
||||||
|
```
|
||||||
|
Expected: exit 0, no load crash (it crashed before on the first example's
|
||||||
|
missing `param_modes`).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run the full render test suite**
|
||||||
|
|
||||||
|
Run: `cargo test --manifest-path $XP/render/Cargo.toml`
|
||||||
|
Expected: PASS — `example_roundtrip` (every example loads, prints to AIL,
|
||||||
|
reparses to the same canonical bytes), `spec_completeness` (every
|
||||||
|
`EXPECTED_VARIANTS` tag observed, including `TermLoop`/`TermRecur`/`TermNew`),
|
||||||
|
`token_balance` (±5%), `splitter_unit`. If `spec_completeness` reports a tag
|
||||||
|
not exercised, the corresponding new example or spec section is missing its
|
||||||
|
construct.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 6: Migrate `mock_full_run.json` and green the harness suite
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `$XP/harness/tests/fixtures/mock_full_run.json`
|
||||||
|
|
||||||
|
The fixture maps `cohort → task → turn → {content, usage}`, where `content` is
|
||||||
|
a string-embedded `.ail.json` program (simulated model output). All are
|
||||||
|
legacy-schema and now fail `ail check`. Migrate the embedded programs to the
|
||||||
|
current schema, **preserving the `usage` fields byte-for-byte** (budget_abort
|
||||||
|
depends on them).
|
||||||
|
|
||||||
|
- [ ] **Step 1: Migrate the programs that must reach green**
|
||||||
|
|
||||||
|
The hard assertions in `mock_full_run.rs` are `json,t3_main_prints,false,2`
|
||||||
|
and `ail,t1_add_three,false,INF`. So:
|
||||||
|
- `json.t3_main_prints.2.content` (turn 2) MUST become a valid current-schema
|
||||||
|
program that passes `ail check` + `ail build` + run — give its fn types the
|
||||||
|
`param_modes`/`ret_mode` fields per Task 1's rule. (Leave
|
||||||
|
`json.t3_main_prints.1.content` as the intentional `"defs":[]` broken first
|
||||||
|
attempt.)
|
||||||
|
- Migrate the other green-intended embedded programs (the first-attempt-green
|
||||||
|
cohort×task cells) the same way, so the fixture is an honest simulation
|
||||||
|
rather than a uniform schema-fail.
|
||||||
|
- `ail.t1_add_three.*.content` stays failing to the turn limit (its `INF` row);
|
||||||
|
let its miss be content-driven, not merely a schema artefact.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify each migrated embedded program checks green standalone**
|
||||||
|
|
||||||
|
For each `content` you migrated to be green, extract it to a temp file and run
|
||||||
|
`target/debug/ail check /tmp/x.ail.json` — expected exit 0. (The harness will
|
||||||
|
also `ail build` it; a green check that fails build means the program is
|
||||||
|
schema-valid but not runnable — fix the body.)
|
||||||
|
|
||||||
|
- [ ] **Step 3: Run the full harness test suite**
|
||||||
|
|
||||||
|
Run: `cargo test --manifest-path $XP/harness/Cargo.toml`
|
||||||
|
Expected: PASS — `mock_full_run` (8 rows; `json,t3_main_prints,false,2` and
|
||||||
|
`ail,t1_add_three,false,INF` both present; `RUN_STATUS=ok`), `budget_abort`
|
||||||
|
(`RUN_STATUS=budget_exceeded`, ≥1 `budget_abort` row), `verify_references`
|
||||||
|
(every `master/tasks/*.reference.ail.json` drives green through real ail+clang),
|
||||||
|
`strip_locations` (5 .stderr fixtures, including `missing field \`type\``).
|
||||||
Reference in New Issue
Block a user