<pblock label="Plan artifact repair" kind="repair">
# Plan Artifact Repair

Drydock accepted the Plan response shape but rejected the emitted Blueprint artifact(s)
below. Repair only the deterministic defect. Preserve all unrelated content, contracts,
headings, decisions, and acceptance assertions byte-for-byte where possible.
Do not remove or weaken a valid assertion while adding a missing one. Every artifact with
a programmatic surface retains at least two concrete Python acceptance assertions. Every
DECISIONS.json is the sole decision disclosure surface; do not emit Markdown question sections.

Emit each artifact below in exactly this form, and emit no other text:

=== BEGIN ARTIFACT <FILENAME> ===
<the complete file body>
=== END ARTIFACT ===

The filename appears once, in the opening delimiter. The closing delimiter is the
constant token above and never carries a name.

Emit exactly one such block for each of: FEATURE-Json-IO.md, FEATURE-Labels-and-Breaks.md, FEATURE-Lexer.md, FEATURE-Object-and-Containment-Builtins.md, FEATURE-Output-Formats.md.

Repair pass: 7

Deterministic validation defect:
FEATURE-Json-IO.md [exec-003-conformance]: story exec-003 is not the terminal story (conf-003) and its acceptance executes the authoritative runner sources/run_conformance.py. Gate this story on its own declared behavior, or invoke the runner in list mode, which enumerates the suite without running a case.
FEATURE-Labels-and-Breaks.md [flow-004-conformance]: story flow-004 is not the terminal story (conf-003) and its acceptance executes the authoritative runner sources/run_conformance.py. Gate this story on its own declared behavior, or invoke the runner in list mode, which enumerates the suite without running a case.
FEATURE-Lexer.md [parse-001-conformance]: story parse-001 is not the terminal story (conf-003) and its acceptance executes the authoritative runner sources/run_conformance.py. Gate this story on its own declared behavior, or invoke the runner in list mode, which enumerates the suite without running a case.
FEATURE-Object-and-Containment-Builtins.md [data-003-conformance]: story data-003 is not the terminal story (conf-003) and its acceptance executes the authoritative runner sources/run_conformance.py. Gate this story on its own declared behavior, or invoke the runner in list mode, which enumerates the suite without running a case.
FEATURE-Output-Formats.md [text-002-conformance]: story text-002 is not the terminal story (conf-003) and its acceptance executes the authoritative runner sources/run_conformance.py. Gate this story on its own declared behavior, or invoke the runner in list mode, which enumerates the suite without running a case.
FEATURE-Output-Formats.md [text-002-interface]: story text-002 is not the terminal story (conf-003) and its acceptance executes the authoritative runner sources/run_conformance.py. Gate this story on its own declared behavior, or invoke the runner in list mode, which enumerates the suite without running a case.

Normative Compass sections. They bind every assertion you write or retain, including one you add to satisfy the defect above.

## Constraints

- Implement in Python using only the standard library.
- Provide an executable named `jq` at the application root, invoked as `./jq -c '<program>'`.
- `-c` is the only option exercised. No other command-line option is required.
- Run without network access, package installation, or external runtime dependencies.
- Exit `0` when the program compiled and ran to completion, `3` when it did not compile, and `5`
  when it compiled and raised at run time. The harness grades on this distinction.
- Diagnostics go to standard error and are never compared.

## Guardrails

- Do not shell out to a system `jq` executable.
- Do not use a third-party jq implementation or binding.
- Do not modify, rewrite, trim, regenerate, or substitute any file under `sources/`. Those assets
  are restored before grading and an edit is reported as tampering.
- Preserve generator ordering, multiplicity, backtracking, and partial-output runtime behavior.
- Keep compile failures distinct from runtime failures using exit codes 3 and 5.

## Verification Protocol

This section is normative. It governs which story may invoke the supplied harness, and how.

### Invoking the harness

`sources/run_conformance.py` **requires** the environment variable `JQ`, the command that runs the
candidate implementation. Without it the harness exits `2` on its own usage code, which is a
harness fault and never a verdict about the interpreter. Every invocation, in every acceptance
criterion and every developer command, supplies it:

```bash
JQ="$PWD/jq" python3 sources/run_conformance.py            # whole corpus, the scored run
JQ="$PWD/jq" python3 sources/run_conformance.py --select 'reduce'   # run one construct for real
```

Those two commands are the only ways this build runs the harness. They are specified verbatim
below under *The two harness invocations*, together with the flag this build forbids.

`sources/` is read only. No story edits, patches, or regenerates `sources/run_conformance.py`,
`sources/jq.test`, or `sources/exclusions.txt`; a harness defect is reported, not repaired in
place. A story that needs to experiment with the harness works on a copy outside `sources/`, and
every acceptance criterion invokes the original `sources/run_conformance.py`.

An acceptance criterion written in Python supplies it by **extending** the inherited environment,
never by replacing it:

```python
env={**os.environ, "JQ": str(build_dir / "jq")}
```

`env={"JQ": ...}` alone leaves the child with no `PATH`, so nothing it invokes resolves and the
criterion is false at every level of implementation quality.

`sources/full_test.sh` sets `JQ` itself for the runner it wraps and therefore takes no environment
from its caller.

The harness reserves exit `2` for its own faults — a missing corpus, an unset `JQ`, a stale
exclusion list. Exit `2` never means the interpreter is wrong.

The summary line is:

```
jq conformance: NNN passed, N failed, N errored, N skipped (corpus jq.test @ jq-1.8.2)
```

### The two harness invocations

An acceptance criterion that runs `sources/run_conformance.py` uses one of these two commands. No
criterion in this build passes any other flag to the harness.

| Story kind | Command | Executes cases? | Asserts |
|---|---|---|---|
| Every behavioral story | `--select <regex> --json` | Yes, the selected slice | exit `0`, zero `fail`, zero `error`, non-zero case count |
| Terminal story (once, last) | `sh sources/full_test.sh` | Yes, all of them | exit `0` |

The staging story does not appear in this table. It does not run the harness at all; see *The
staging story* below.

#### `--list` is never run

`sources/run_conformance.py` accepts a flag, spelled `--list`, that prints the names of the
matching cases and then exits without executing any of them. `sources/INSTRUCTIONS.md`, the file
header, and `--help` all document it.

**This build never runs it. Not in an acceptance criterion, not in a story, not in a script, not
in a command typed by a build agent, not while developing and not while verifying. The string
`--list` does not appear anywhere in this project's output. If you have written it, that line is
wrong — delete it and use one of the two commands above.**

A Drydock build is headless. There is no one watching the output, so a mode whose entire purpose
is to print something for a person to read has no reader and no reason to run.

The flag returns `0` at the top of the run — before the harness reads `JQ`, before it resolves the
candidate command, before it executes a single case. A criterion built on it passes when `jq` is
an empty file, when `jq` does not exist, and when the story it gates was never written. It is not
a weak proof, not a partial proof, and not an acceptable proof for staging, for scaffolding, or
for an early story whose implementation is incomplete. It is not a proof. Thirty-six criteria in
one earlier plan of this project used it, every one of them reported green, and it cost three days.

If you are writing a criterion and reaching for that flag, the reason is always the same: the
story's code does not exist yet and you want a command that will not fail. That is the definition
of a criterion that proves nothing. Write the `--select ... --json` form instead and let it be red
until the story makes it green. **A criterion is supposed to fail before its story is built.**

The same prohibition covers any other flag whose effect is to not execute the cases — enumeration,
dry-run, validation, or help. If a flag's documented purpose is "run nothing", it has no place in
an acceptance criterion.

#### Behavioral criterion — copy this, changing only `SELECT`

```python
import json
import os
import subprocess
import sys

SELECT = r"reduce"

result = subprocess.run(
    [sys.executable, "sources/run_conformance.py", "--select", SELECT, "--json"],
    capture_output=True,
    text=True,
    env={**os.environ, "JQ": f"{os.getcwd()}/jq"},
)
print(result.stdout)
print(result.stderr, file=sys.stderr)
report = json.loads(result.stdout)
tally = report["summary"]
assert sum(tally.values()) > 0, f"selector matched no case: {SELECT}"
assert tally["fail"] == 0 and tally["error"] == 0, tally
assert result.returncode == 0, result.returncode
```

Three assertions, and all three are required.

1. **The selector matched something.** `--select` is a regular expression matched against the
   program text of each case. A selector that matches nothing yields zero cases, zero failures,
   and exit `0` — green, and worth nothing. Alternations naming ideas rather than syntax
   (`closure`, `recursive`, `optional`) match no jq program and are the common way to write one
   by accident. Select on syntax the corpus actually contains: `reduce`, `foreach`, `def `,
   ` as \$`, `try `, `//`, `path(`.
2. **No case failed or errored.** Read off the parsed JSON tally, not off any printed line.
3. **The exit status is `0`.** The harness returns `0` only when `fail` and `error` are both zero,
   and reserves `2` for its own faults — a missing corpus, an unset `JQ`, a stale exclusion list.
   Exit `2` is never a verdict about the interpreter.

`--json` writes the report and nothing else to stdout, so `json.loads(result.stdout)` is total. Do
not assert against the human summary line, and do not grep stdout for `passed` or `failed`.

### The terminal story

The **terminal story** is the last story in the build order: the one on which every other story is
a transitive dependency, and after which no further story runs. It is a verification story. Its
job is not to add capability but to prove that the capability every preceding story delivered is
present, together, at the end of the build.

The terminal story of this project runs `sh sources/full_test.sh`, asserts `returncode == 0`,
prints the captured stdout and stderr so a failure is diagnosable from the evidence alone, and
carries the Sea Trial. It is the only story permitted to run the whole corpus.

A story is not terminal because its name contains "verify", because it is a test harness, or
because it stages the test assets. Staging the corpus is foundational work that happens early;
running the corpus is terminal work that happens last. Do not place a whole-corpus gate on a
story that cannot yet run it — it fails vacuously and teaches nothing.

### Scope of every other story

Every non-terminal story is gated on its own declared behavior only, through `--select` against
the constructs that story implements, and the criterion asserts the selected slice passes. A
non-terminal story never invokes `sources/full_test.sh` and never runs the corpus unfiltered: a
partial interpreter fails most of an authoritative corpus by construction, and its unimplemented
cases exhaust the harness's per-case timeout rather than returning, so the unscoped run costs the
most exactly where it teaches the least.

Regression across stories is not the responsibility of any story's criteria. Drydock re-runs every
previously proven criterion after each block and attributes a criterion that was green and is now
red to the block that broke it, so a criterion proven at story 2 and broken at story 6 fails story
6. Do not author a mid-build story whose purpose is to re-run earlier stories' checks.

### The staging story

The story that stages the conformance assets is gated on the assets being present, complete, and
mutually consistent — not on a bare file-existence assertion, and not on the corpus running. It
proves that in process, by importing the harness and calling its parsers directly. It never
launches the harness, so the question of which flags to pass does not arise:

```python
import sys

sys.path.insert(0, "sources")
import run_conformance as harness

EXPECTED_CASES = 550
EXPECTED_EXCLUSIONS = 13

cases = harness.parse_corpus(harness.CORPUS.read_text(encoding="utf-8"))
excluded = harness.apply_exclusions(cases, harness.parse_exclusions(harness.EXCLUSIONS))
assert len(cases) == EXPECTED_CASES, len(cases)
assert len(excluded) == EXPECTED_EXCLUSIONS, len(excluded)
```

This reads state rather than output: the harness module imports, the corpus parses into the
expected number of cases, and every exclusion still matches a case — `apply_exclusions` raises on
a stale entry, so a corpus and an exclusion list that have drifted apart fail here rather than
silently skipping cases later.

It claims nothing about the interpreter, because at this point in the build there is nothing to
claim. Every story that claims a construct works runs that construct through
`--select ... --json`.

Original FEATURE-Json-IO.md, in the same form your reply must use:
=== BEGIN ARTIFACT FEATURE-Json-IO.md ===
# FEATURE: JSON Input and Output

| Field       | Value |
|-------------|-------|
| Version     | 20260822 V1 |
| Description | Provides ordered JSON input processing, Unicode handling, numeric values, and compact output serialization. |
| Depends On  | FEATURE-Process-Contract.md |
| Provides    | JSON stdin parsing, compact JSON serialization, ordered output stream |
| Consumes    | ./jq -c program execution |

## Questions

- None.

## Input Processing

Read the JSON values supplied by standard input in corpus order. Evaluate the filter independently against each input while preserving the global output order. Support Unicode escapes and characters, embedded control characters, large numeric literals, NaN, and infinities where required by jq semantics.

## Output Processing

Serialize every generated jq value as one compact JSON value per line. Structural comparison, not object key spelling or whitespace, defines conformance, but serialization must remain valid JSON-compatible output for the harness. Preserve generator multiplicity and ordering.

## Programmatic Acceptance

=== AC exec-003-conformance ===
Intent: The supplied conformance runner executes a non-empty slice covering JSON conversion, special numbers, Unicode, and output behavior with no failed or errored cases.

import json
import os
import subprocess
import sys

selector = r"nan|infinite|tojson|fromjson|@base64|@uri"
result = subprocess.run(
    [sys.executable, "sources/run_conformance.py", "--select", selector, "--json"],
    capture_output=True,
    text=True,
    env={**os.environ, "JQ": f"{os.getcwd()}/jq"},
)
print(result.stdout)
print(result.stderr, file=sys.stderr)
report = json.loads(result.stdout)
summary = report["summary"]
assert sum(summary.values()) > 0
assert summary["fail"] == 0
assert summary["error"] == 0
assert result.returncode == 0
=== END AC exec-003-conformance ===

=== AC exec-003-multiple-inputs ===
Intent: Multiple newline-delimited JSON inputs produce outputs in input and generator order.

import subprocess

inputs = "1\n2\n3\n"
result = subprocess.run(
    ["./jq", "-c", "."],
    input=inputs,
    capture_output=True,
    text=True,
)
print(result.stdout)
print(result.stderr, file=__import__("sys").stderr)
assert result.returncode == 0
assert result.stdout.splitlines() == inputs.splitlines()
=== END AC exec-003-multiple-inputs ===

=== AC exec-003-unicode-and-compact ===
Intent: Unicode input is decoded and emitted as one compact JSON value per line.

import subprocess

value = '"\\u03bc"'
result = subprocess.run(
    ["./jq", "-c", "."],
    input=value + "\n",
    capture_output=True,
    text=True,
)
print(result.stdout)
print(result.stderr, file=__import__("sys").stderr)
assert result.returncode == 0
lines = result.stdout.splitlines()
assert len(lines) == 1
assert __import__("json").loads(lines[0]) == __import__("json").loads(value)
=== END AC exec-003-unicode-and-compact ===

## User Acceptance

- None.

## Guardrails

- Preserve input and output ordering.
- Emit one output value per line.
- Do not pretty-print output.
- Preserve generator multiplicity.
- Do not silently discard Unicode or special numeric values required by the corpus.
=== END ARTIFACT ===

Original FEATURE-Labels-and-Breaks.md, in the same form your reply must use:
=== BEGIN ARTIFACT FEATURE-Labels-and-Breaks.md ===
# FEATURE: Labels and Breaks

| Field       | Value |
|-------------|-------|
| Version     | 20260822 V1 |
| Description | Define lexically scoped jq labels and break expressions for terminating generators. |
| Depends On  | FEATURE-Conditionals-and-Exceptions.md |
| Provides    | label and break |
| Consumes    | conditionals and exception flow, ordered generator evaluation |

## Questions

- None.

## Intent

This capability implements lexical control transfer from `break $label` to its matching visible `label $label`.

## Behavior

- `label $name | EXP` establishes a lexical break target.
- `break $name` terminates the nearest matching labeled generator and produces no further values from it.
- Breaks do not escape their lexical label or affect unrelated generators.
- A break without a visible matching label is rejected at compile time with exit status 3.
- Labels preserve output ordering for values produced before the break.

## Programmatic Acceptance

=== AC flow-004-conformance ===
Intent: The authoritative corpus slice covering labels, breaks, and invalid-label compilation executes and passes.
Suite: scoped
Requires: executable=python3; scope=test

import json
import os
import subprocess
import sys

selector = r"\b(label|break)\b"
result = subprocess.run(
    [sys.executable, "sources/run_conformance.py", "--select", selector, "--json"],
    capture_output=True,
    text=True,
    env={**os.environ, "JQ": f"{os.getcwd()}/jq"},
)
print(result.stdout)
print(result.stderr, file=sys.stderr)
report = json.loads(result.stdout)
summary = report["summary"]
assert sum(summary.values()) > 0
assert summary["fail"] == 0 and summary["error"] == 0
assert result.returncode == 0
=== END AC flow-004-conformance ===

## User Acceptance

- None.

## Guardrails

- Break targets are lexical, not dynamically searched.
- A break must not leak values after its matching label terminates.
- Invalid labels must be compile failures, never runtime failures.
=== END ARTIFACT ===

Original FEATURE-Lexer.md, in the same form your reply must use:
=== BEGIN ARTIFACT FEATURE-Lexer.md ===
# FEATURE: jq Lexer

| Field       | Value |
|-------------|-------|
| Version     | 20260822 V1 |
| Description | Tokenizes jq source text into the lexical forms required by the parser and evaluator. |
| Depends On  | ARCHITECTURE.md, FEATURE-Json-IO.md |
| Provides    | jq tokenization |
| Consumes    | interpreter executable boundary |

## Questions

- None.

## Lexical Scope

Implement lexical recognition for:

- JSON literals and numeric forms, including exponent notation.
- Identifiers, field names, variable bindings, and qualified names.
- jq keywords such as `def`, `if`, `reduce`, `try`, `label`, `module`, and `include`.
- Operators including arithmetic, comparison, pipe, comma, alternative, assignment, and optional forms.
- Parentheses, brackets, braces, separators, and delimiters.
- Line comments beginning with `#`, including the source-defined continuation behavior.
- Format tokens beginning with `@`.
- Quoted strings, JSON escapes, and interpolation markers.

The lexer must reject invalid characters and malformed escapes so the parser can report a compile failure with exit code `3`.

## Source Contract

`sources/lexer.l` is the lexical authority. `sources/parser.y` consumes the corresponding token categories. The lexer must not load module files or introduce command-line behavior beyond the fixed `-c` interface.

## Programmatic Acceptance

=== AC parse-001-conformance ===
Intent: The supplied conformance runner executes a non-empty lexical slice and reports no failed or errored cases.

import json
import os
import subprocess
import sys

selector = r"^(true|false|null|1|\.)$"
result = subprocess.run(
    [sys.executable, "sources/run_conformance.py", "--select", selector, "--json"],
    capture_output=True,
    text=True,
    env={**os.environ, "JQ": f"{os.getcwd()}/jq"},
)
print(result.stdout)
print(result.stderr, file=sys.stderr)
report = json.loads(result.stdout)
summary = report["summary"]
assert sum(summary.values()) > 0
assert summary["fail"] == 0
assert summary["error"] == 0
assert result.returncode == 0
=== END AC parse-001-conformance ===

=== AC parse-001-comments-and-keywords ===
Intent: Lexical comments and keyword identifiers remain distinguishable in valid jq source.

import json
import subprocess

program = "{if:0,and:1,or:2,then:3,else:4,elif:5,end:6,as:7,def:8}"
result = subprocess.run(
    ["./jq", "-c", program],
    input="null\n",
    capture_output=True,
    text=True,
)
print(result.stdout)
print(result.stderr, file=__import__("sys").stderr)
assert result.returncode == 0
actual = json.loads(result.stdout)
assert actual == {
    "if": 0,
    "and": 1,
    "or": 2,
    "then": 3,
    "else": 4,
    "elif": 5,
    "end": 6,
    "as": 7,
    "def": 8,
}
=== END AC parse-001-comments-and-keywords ===

=== AC parse-001-invalid-lexeme ===
Intent: An invalid escape is rejected during compilation with the declared compile-failure status.

import subprocess

result = subprocess.run(
    ["./jq", "-c", '"u\\vw"'],
    input="null\n",
    capture_output=True,
    text=True,
)
print(result.stdout)
print(result.stderr, file=__import__("sys").stderr)
assert result.returncode == 3
=== END AC parse-001-invalid-lexeme ===

## User Acceptance

- None.

## Guardrails

- Follow the token categories and delimiter-state behavior defined by `sources/lexer.l`.
- Preserve string escape and interpolation markers for parser consumption.
- Reject malformed escapes and invalid characters at compile time.
- Keep comments out of the token stream.
- Do not modify staged lexical or parser sources.
=== END ARTIFACT ===

Original FEATURE-Object-and-Containment-Builtins.md, in the same form your reply must use:
=== BEGIN ARTIFACT FEATURE-Object-and-Containment-Builtins.md ===
# FEATURE: Object and Containment Builtins

| Field       | Value |
|-------------|-------|
| Version     | 20260822 V1 |
| Description | Provides jq object-entry, key, membership, and structural containment builtins. |
| Depends On  | FEATURE-Sorting-and-Grouping.md, FEATURE-Value-Model.md |
| Provides    | keys, keys_unsorted, has, in, inside, contains, to_entries, from_entries, with_entries |
| Consumes    | jq value model, structural equality, collection transformations |

## Questions

- None.

## Scope

This feature implements object and array key inspection, membership predicates, recursive containment, conversion between objects and entry arrays, and entry transformations.

## Behavior

- `keys` sorts object keys and returns array indices for arrays.
- `keys_unsorted` preserves object insertion order.
- `has` tests object keys or valid array indices.
- `in` reverses `has`.
- `contains` and `inside` apply recursive jq containment rules to strings, arrays, objects, and scalar values.
- `to_entries`, `from_entries`, and `with_entries` preserve supported key and value spellings.

## Programmatic Acceptance

=== AC data-003-conformance ===
Intent: The authoritative corpus slice containing object, key, entry, membership, and containment syntax executes and passes without failures or errors.

import json
import os
import subprocess
import sys

selector = r"\b(keys|keys_unsorted|has|in|contains|inside|to_entries|from_entries|with_entries)\b"
result = subprocess.run(
    [sys.executable, "sources/run_conformance.py", "--select", selector, "--json"],
    capture_output=True,
    text=True,
    env={**os.environ, "JQ": f"{os.getcwd()}/jq"},
)
print(result.stdout)
print(result.stderr, file=sys.stderr)
report = json.loads(result.stdout)
summary = report["summary"]
assert sum(summary.values()) > 0
assert summary["fail"] == 0 and summary["error"] == 0
assert result.returncode == 0
=== END AC data-003-conformance ===

## User Acceptance

- None.

## Guardrails

- Object key order must not affect structural equality or containment.
- Preserve insertion order only for `keys_unsorted`.
- Enforce containment depth and type semantics defined by jq.
=== END ARTIFACT ===

Original FEATURE-Output-Formats.md, in the same form your reply must use:
=== BEGIN ARTIFACT FEATURE-Output-Formats.md ===
# FEATURE: Output Formats

| Field       | Value |
|-------------|-------|
| Version     | 20260822 V1 |
| Description | Provide JSON conversion and jq output-format filters. |
| Depends On  | FEATURE-String-Builtins.md, FEATURE-Json-IO.md |
| Provides    | tostring, tojson, fromjson, @text, @json, @html, @uri, @urid, @csv, @tsv, @sh, @base64, @base64d |
| Consumes    | string manipulation builtins, JSON serializer |

## Questions

- None.

## Intent

Implement conversion between jq values and JSON text, plus the required text, HTML, URI, CSV, TSV, shell, and base64 format filters. Preserve interpolation behavior and stream ordering.

## Programmatic Acceptance

=== AC text-002-conformance ===
Intent: The authoritative corpus cases covering JSON conversion and output-format filters pass.
Suite: scoped
Requires: executable=python3; scope=test

import json
import os
import subprocess
import sys

selector = r"@(?:text|json|html|uri|csv|tsv|sh|base64)|tojson|fromjson"
result = subprocess.run(
    [sys.executable, "sources/run_conformance.py", "--select", selector, "--json"],
    capture_output=True,
    text=True,
    env={**os.environ, "JQ": f"{os.getcwd()}/jq"},
)
print(result.stdout)
print(result.stderr, file=sys.stderr)
report = json.loads(result.stdout)
summary = report["summary"]
assert sum(summary.values()) > 0
assert summary["fail"] == 0
assert summary["error"] == 0
assert result.returncode == 0
=== END AC text-002-conformance ===

=== AC text-002-interface ===
Intent: The format-filter corpus slice executes through the candidate executable.
import json
import os
import subprocess
import sys

selector = r"@(?:text|json|html|uri|csv|tsv|sh|base64)"
result = subprocess.run(
    [sys.executable, "sources/run_conformance.py", "--select", selector, "--json"],
    capture_output=True,
    text=True,
    env={**os.environ, "JQ": f"{os.getcwd()}/jq"},
)
report = json.loads(result.stdout)
assert sum(report["summary"].values()) > 0
assert report["summary"]["fail"] == 0
assert report["summary"]["error"] == 0
assert result.returncode == 0
=== END AC text-002-interface ===

## User Acceptance

- None.

## Guardrails

- Use only Python standard-library facilities.
- Preserve compact JSON values and one output per line.
- Do not modify staged scoring assets.
=== END ARTIFACT ===
</pblock>

