Files
notarius/docs/adr/0016-feedback-aware-module-requested-retries.md

4.0 KiB

ADR-0016: Use feedback-aware module-requested retries

Status: Accepted Date: 2026-08-28

Context

An LLM-backed module can discover that a structurally valid model response is unsafe while translating it into a typed candidate, before the ordinary validator chain runs. Semantic registry reconciliation is the first such case: the shared core can identify invalid duplicate-group proposals, and typed application can reject a domain-incompatible group while preserving a safe partial result. Repeating the original request without the rejected response or corrective explanation gives the model no information with which to improve.

The existing feedback-aware validation mechanism already establishes the safe correction protocol, but module-owned retry directives also carry internal reason codes, operator messages, and fallback diagnostics. Those values are not model instructions. Some module retry conditions, including exhausted structured-output repair, also have no valid exact response to append.

Decision

An LLM-backed normalizer may attach optional, bounded model-facing correction guidance to a module-requested retry. Guidance is a separate contract field; the framework never derives it from a reason code, operator message, diagnostic, or error. A feedback-capable directive must include the exact model candidate that controlled the safe fallback and must use single_response_v1.

The artifact-neutral producer-attempt state machine constructs the correction from that exact latest response and the supplied guidance. The producer rebuilds its complete ordinary request and appends the response as one assistant message and the guidance as one user message. Earlier attempts do not accumulate, and the attempt consumes the same configured stage retry budget as operational, structural, validation, and feedback-free module retries.

A module retry without guidance remains valid and starts a fresh attempt. This is the required behavior when no valid model candidate exists, including after structured-output repair is exhausted. If feedback is supplied without a valid supported candidate, the framework fails the module contract rather than retrying blindly or inventing guidance.

After retry exhaustion, the normalizer's safe fallback continues through its validator chain. Safe semantic groups may remain applied, unsafe groups remain separate, and bounded fallback diagnostics may explain the process degradation. Exact responses and correction text remain attempt-local and are excluded from ordinary errors, warnings, manifests, receipts, caches, and checkpoints.

This decision extends, rather than supersedes, ADR-0014: both correction sources use the same transport-neutral payload, replacement-request semantics, outer retry budget, and sensitive-data boundary.

Alternatives considered

  • Continue blind module retries. This preserves a smaller contract but wastes the module's deterministic diagnosis and commonly repeats the same defect.
  • Convert module safety checks into validators. Typed reconciliation must apply only safe proposal groups and retain a fallback before validation; moving artifact-owned translation and application policy into validators would blur stage ownership.
  • Copy the retry reason or operator message into the model request. Those values are written for provenance and humans, can contain opaque internal labels, and do not reliably describe a correct replacement.
  • Require feedback for every module retry. Structural failures may have no valid exact candidate, so this would either prevent useful fresh retries or fabricate prior-response material.

Consequences

The normalize retry contract and generic producer-attempt directive gain an optional correction-guidance field and candidate-pairing validation. Modules that use it must provide semantically meaningful bounded prose and an exact candidate. Registry reconciliation maintains separate operator and model renderers, and policy fingerprints change so checkpoints created under blind retry behavior are not reused.