Diagnostic Output Contracts
Tracker references: pm-cha95z, pm-5t33or, pm-f05lsg, pm-h8tpeh, and pm-m4uyyj.
Agent Quick Context
Failures are context-management surfaces. Every diagnostic family now declares a format-aware token ceiling and one degradation ladder in the public SDK:
| Class | Text | JSON | Corrective action that survives degradation |
|---|---|---|---|
error |
768 | 2000 | required action, retry/domain, or next step |
warning |
768 | 2000 | required action, retry/domain, or next step |
validation_summary |
1500 | 3000 | required action, retry/domain, or next step |
recovery_bundle |
768 | 2000 | required action, retry/domain, or next step |
The smallest explicit ceiling is 192 estimated tokens. At that floor, the projector may reduce the diagnostic to its code, required action, compact recovery, and exit status. It never removes the first corrective action.
SDK Contract
Use the public contract surface rather than maintaining a package-local error budget:
import {
PM_DIAGNOSTIC_OUTPUT_BUDGET_CONTRACTS,
projectPmDiagnosticOutput,
projectPmDiagnosticText,
resolvePmDiagnosticOutputBudget,
} from "@unbrained/pm-cli/sdk/contracts";
const contract = resolvePmDiagnosticOutputBudget("error");
const projected = projectPmDiagnosticOutput(
{
code: "invalid_argument_value",
required: "Use --status open and retry.",
recovery: { suggested_retry: "pm list --status open" },
detail: "The supplied status is not declared.",
exit_code: 2,
},
{ maxEstimatedTokens: contract.minimum_max_estimated_tokens },
);
const text = projectPmDiagnosticText(
"A long rendered diagnostic",
"Use --status open and retry.",
).output;
The JSON projector orders code, required, recovery, and next steps before
explanation. Untruncated diagnostics add no per-call receipt overhead; their
binding declaration is discoverable from pm contracts --full --json under
diagnostic_output_contracts. When degradation occurs, the returned
diagnostic_output receipt records the effective budget, original and emitted
estimates, applied stages, and omitted top-level fields. Minimal fallbacks bound
the named omission list and disclose any additional count through
omitted_fields_overflow_count.
Structured CLI refusals also include a compact refusal identity with the
failing command/flag/operand surface, rejected scalar when observable, complete
legal domain when one exists, and the process exit code. Recovery-bearing
errors use the recovery_bundle diagnostic class. Collection degradation may
compact explanatory domains inside recovery, but refusal.legal_domain
remains complete and recovery.suggested_retry_args is atomic: the projector
either retains the executable argv or removes the recovery rather than slicing
it into a dead command.
The deterministic ladder is:
- full diagnostic;
- omit explanation;
- limit diagnostic collections;
- compact recovery to actionable keys;
- retain the action-only envelope.
Human diagnostics lead with What is required and next steps before explaining
what happened. If their declared ceiling binds, the compact text still begins
with the required action, retains the first identifying line (up to 320 UTF-8
bytes), and points to structured JSON for the bounded recovery envelope. The
first line should name the specific failure, such as Error: Unknown option --label. Oversized caller-input echoes are discarded before this identity;
the retained identity and corrective action share the binding byte budget.
The text projector strips terminal escape sequences and replaces remaining
control characters before measuring output, including short diagnostics that
fit the budget. Line breaks and ordinary indentation are preserved.
Executable Assurance
pnpm quality:recovery-closure builds the current CLI and replays 117 refusal
contracts in isolated trackers: 18 closed-domain rows, 88 required-argument
omissions derived from core executable positional signatures, seven
closed-action families, and four tracker-preflight states. Package-owned
commands enter executable coverage when their package runtime is active rather
than being misreported as core. Ten representative, high-frequency failure
paths are also ratcheted by
scripts/release/diagnostic-output-baseline.json. The gate requires every row
to remain within the SDK-declared JSON ceiling and retain a mechanically
actionable correction. It reports the aggregate original and emitted token
estimates without claiming a reduction when no degradation was required.
The baseline is a coverage ratchet, not permission to weaken a ceiling. Its negative control requires a missing baseline probe to fail. The existing refusal-closure negative controls independently prove that incomplete domains, broken retries, and malformed recovery envelopes remain blocking findings. The grammar corpus additionally hashes authoritative tracker state around each refusal; schema, items, history, settings, and package state must not change. Ephemeral runtime lock/cache directories are excluded from that semantic snapshot.
The complete error-code census currently retains executable evidence for 18
catalog rows across 17 canonical groups. Two of those rows are author-manifest
schema findings reached through a real pm health --full --strict-exit --json
process: an unknown top-level key and omitted canonical pm version bounds. The
remaining rows stay explicit uncovered obligations in
the generated census; the ratchet does not
turn partial catalog closure into an approval claim.
Run the focused proof with:
pnpm build
node scripts/release/refusal-closure-gate.mjs
node scripts/run-tests.mjs test -- \
tests/unit/sdk/agent-output-contracts.spec.ts \
tests/unit/cli/error-guidance.spec.ts \
tests/unit/scripts/refusal-closure-gate.spec.ts