Skip to content

An outer <PrintErrors> does not print a failure an <Output> region decided #327

Description

@taras

Motivation

architecture.md is authoritative on the error model, and its mode table says:

Mode An undecided error… Installed by
output fails the run; <PrintErrors> can print instead every <Output> region

§6.8.1 says the same from the other side: a failure an output decision selected is deliberately not in the never-printed list — "the region it left has already stopped, so printing it resumes nothing." throw is named as the one mode a boundary does not replace.

On 511776e an outer <PrintErrors> does not print such a failure. The run fails instead. The contract is the architecture's; this is the engine not meeting it.

Reproduction

Shared fixture — a name that resolves to nothing, which raises an ordinary printed error under print:

<!-- components/OutFail.md -->
<Output>before <Nope /> after</Output>
<!-- components/Holder.md -->
<Output><Content /></Output>

Control — print at the root works.

<PrintErrors>
<Nope />
</PrintErrors>

TAIL REACHED

exit 0; stdout carries <!-- ERROR: Failed to import component Nope … --> and TAIL REACHED. Correct.

Case 1 — the failure is in the callee's own <Output> region.

<PrintErrors>
<OutFail />
</PrintErrors>

TAIL REACHED

Expected: the boundary prints one error whose cause is the original failure, and TAIL REACHED renders.
Actual: exit 1. stdout holds only the partial text before ; the message goes to stderr; TAIL REACHED never renders.

Case 2 — the failure is projected into a callee's <Output> region.

<PrintErrors>
<Holder><Nope /></Holder>
</PrintErrors>

TAIL REACHED

Expected: §6.3 says "the error mode is captured at the expansion site and carried across", and the expansion site here is inside <PrintErrors> — so this should print for that reason alone, independently of the output question.
Actual: exit 1, nothing on stdout, TAIL REACHED never renders.

Where to look

decidedByOutput() (packages/core/src/errors.ts:264) exists precisely to distinguish an output decision from a throw decision at a printing boundary, and its comment states the intended difference. Its only consumer is expand.ts:2292, on the ContentExpansionFailure branch. Case 1 does not reach that branch at all, and case 2 reaches it but still fails — so the two cases may not share a cause. Both should be checked rather than assumed to be one fix.

Partial output

Case 1 shows the partial-output rule already working: before reached the output stream before the failure. Whatever fixes printing must keep that — the region's already-rendered text stays, and printing adds the error after it rather than replacing it.

Acceptance criteria

  • An outer <PrintErrors> turns a failure an <Output> region decided into exactly one printed error whose cause is the complete original failure, and the run continues past the boundary.
  • The same holds whether the failure arose in the callee's own <Output> region or in content projected into one.
  • A throw decision is still never printed — documentation and value roots keep failing through a boundary.
  • Text a failing region had already rendered still reaches the output stream, and the printed error does not replace it.
  • A durability failure is still never printed.
  • Tests discriminate the three cases above by exit status and by whether the tail after the boundary renders — an assertion on stderr alone would pass today.

Impact

Reported while synchronizing the #181 living end-goal target (#292). The workflow documents describe the architectural behavior, as architecture.md is authoritative, and classify this as missing pending this issue. No workflow document writes <PrintErrors> today, so nothing is blocked on it — but a stage that wants to survive a failed region cannot, and the target's error-mode table would otherwise have to contradict the registry.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions