Skip to content

Latest commit

 

History

History
127 lines (110 loc) · 7.3 KB

File metadata and controls

127 lines (110 loc) · 7.3 KB

CLI machine-readable contract

← CLI contract index

Exit codes

Code Meaning Examples
0 success clean check, compiled artifact produced, reconstructed source produced
1 source/user error parse error, validation error, ambiguous input, unknown input kind, unreadable input, refused downgrade, non-Workshop convert input, a deliberate LPP provider refusal (provider-refusal-<refusalCode>), an owner-side project load failure (project-load-failed)
2 usage error unknown command/flag, missing option value, missing/unknown convert --target
3 recognized but unsupported .opy stdin via the explicit adapter fallback (default path is native), package-manager-managed installation for update self, unsupported platform for update self, a convert reconstruction rejection (a construct outside the declared OPY/OSTW reconstruction surface), an LPP capability the provider did not negotiate (capability-unavailable)
4 internal/environment failure catalog corruption, adapter bridge missing, I/O failure writing output, update network/checksum/extraction failure, provider transport/process failures (provider-spawn, provider-io, provider-timeout, provider-exited, provider-malformed, jsonrpc-error), provider resolution failures (provider-missing, provider-offline, provider-download, provider-integrity, provider-install, provider-unsupported-platform)

Exit codes are deterministic for identical inputs and configuration and are also carried inside the JSON envelope (exit field), so agents never need to infer them from process state alone.

stdout / stderr ownership

  • Text mode: the command result goes to stdout; diagnostics go to stderr.
  • JSON mode: exactly one envelope goes to stdout; stderr stays empty on success. Usage errors are the only case that writes to stderr without an envelope (exit 2).
  • wright compile without -o writes the raw artifact to stdout in text mode; in JSON mode the artifact is the result.output.text field of the envelope.

wright-result/v1 envelope

{
  "wright": { "version": "0.1.0", "contract": "wright-result/v1" },
  "command": "analyze",
  "ok": true,
  "exit": 0,
  "diagnostics": [],
  "result": {
    "program": { "origin": { "kind": "workshop", "locale": "en-us" }, "rules": 2 },
    "facts": {
      "symbols": [{ "id": 0, "kind": "globalVariable", "name": "counter", "usage": { "reads": 1, "writes": 1, "calls": 0, "rules": 1 } }],
      "rules": [{ "id": 0, "name": "loop", "controlFlow": { "blocks": 4, "edges": 4, "loopBlocks": 1, "waitBlocks": 1 }, "elements": 21, "conditionElements": 0, "conditions": [] }],
      "cost": { "elementCount": 21, "counts": { "rules": 1, "conditions": 0, "actions": 7, "waits": 1 } },
      "risks": [{ "code": "min-wait-loop", "severity": "warning", "evidence": "static-indicator", "message": "...", "span": { "file": 0, "path": "program.ws", "start": { "line": 11, "col": 9 }, "end": { "line": 11, "col": 20 } } }],
      "persistentObjects": []
    }
  }
}

analyze facts layers Workshop cost/size over the semantic queries (#445): cost.elementCount is the canonical workshop-rs element count (an exact structural size measurement — null with unavailableReason when the counter does not model a construct), cost.counts holds always-computable structural counts, each rules entry adds the rule's elements and its conditions trees (element count + span per condition), risks lists the registry findings whose rules carry a performance or stability tag with their evidence class, and persistentObjects reports the persistent-object facts (#429).

Stable contract fields: wright.contract, command, ok, exit, diagnostics[].code/stage/severity/span/source, and each command's result shape. Human-readable message wording is explicitly not part of the machine contract.

Diagnostic codes are stable per stage: parse-error, unknown-*, unsupported-construct, settings-invalid, settings-placement (frontend), settings-unknown-key, settings-unknown-value (validation), convert-error/ lower-error (lowering), validation-error (validation), input-*/ stdin-* (discovery), output-io and the compile-time client-import diagnostics target-element-limit / element-count-unavailable (emission), analysis findings reuse the analyzer's codes — including the name-addressing refusals unknown-symbol, ambiguous-symbol, unknown-rule, and ambiguous-rule (#429) — and *-internal / *-unavailable (internal). source-provider-unavailable marks the explicit DEL/OSTW provider boundary and is reported at the internal stage. Provider failures keep the provider's typed classification in the diagnostic code, on the source-provider seam and in providerSemanticRename/providerValidateEdit mutation results alike: an LPP refusal is provider-refusal-<refusalCode> (a Wright-originated refusal keeps its own code, e.g. session-config-changed), a capability gap is capability-unavailable, and transport/process failures keep their provider-* codes — a consumer classifies the failure from code/stage without parsing message (#569, #570). Provider-edit mutation results also carry the refusal's refusalCode or the failure's typed code verbatim in provider_code. A convert reconstruction rejection carries the language-owned reconstructor's stable code (e.g. unsupported-per-player-loop from wright-opy, reconstruct-unsupported-action from an OSTW provider) with stage reconstruction; convert-input-kind (discovery) rejects non-Workshop convert input, and manifest-error/catalog-error from a reconstructor map to the internal stage.

The native .opy frontend's builtin-resolution stage adds the stable codes unknown-action, unknown-value, unknown-member, invalid-arity, invalid-receiver, enum-domain-mismatch, action-in-value-position, value-in-action-position, invalid-call-context, and invalid-iterable (semantic resolution against the OPY compatibility manifest, #109; all source-located). Named/keyword argument binding adds unknown-keyword, duplicate-argument, missing-argument, positional-after-keyword, keyword-required, keyword-unsupported, and invalid-argument (variable-required parameters; #110).

wright-result/v1 evolution

The envelope follows the same rule as wright-agent/v1: additive optional result fields are permitted within v1; removing or renaming a field, changing a field's type or meaning, or changing the envelope or exit-code model requires a new major contract such as wright-result/v2.

One recorded exception applies, decided before the 1.0 contract freeze (#134): the lint result's rules member lists only each rule's id and effectiveSeverity (#431). Full rule metadata — summary, rationale, documentation, known limits, evidence, tags — is served once by the lintRules agent operation instead of being inlined into every lint result.

Determinism

For identical inputs and configuration, JSON output is byte-deterministic (no timestamps, no environment-dependent ordering). Input identity is the SHA-256 of the input bytes (result.output.input_identity); for provider-backed directory targets, the owner supplies the identity of its selected primary source text. Emitted artifacts carry their own SHA-256 (result.output.sha256).