9.3 KiB
Subprocess Integration Contract
Status
Implemented.
Purpose
Make Notarius straightforward to invoke as a subprocess from an orchestrator such as Narratio. A caller should be able to run a configured pipeline, discover the published output bundle without parsing human prose or scanning a directory, and hand selected structured artifacts to a later stage.
This work strengthens the public CLI boundary. It does not turn Notarius into a Go library, embed Narratio-specific behavior, or change pipeline execution and artifact semantics.
Desired End State
A subprocess caller can:
- validate a Notarius configuration and selected pipeline before execution;
- invoke
notarius runwith explicit input, output-root, session, and reference arguments; - request one versioned, machine-readable success result on standard output;
- use that result to locate the published output bundle;
- discover normalized lane payloads through the bundle's authoritative
index.json; - distinguish process failure from successful partial pipeline outcomes; and
- record Notarius run provenance in its own manifest without depending on internal packages, cache formats, debug formats, or human-readable messages.
The existing human-oriented command output remains the default for interactive use.
Machine-Readable Run Result
notarius run supports --json. On success, the flag makes standard output
contain exactly one JSON object followed by a newline. No human-oriented status
line is mixed into that stream.
The result uses the schema identity notarius.run-result.v1 and contains:
| Field | Presence | Meaning |
|---|---|---|
schema_version |
Required | Exactly notarius.run-result.v1. |
run_id |
Required | The Notarius run identifier. |
pipeline_id |
Required | The effective pipeline identifier. |
output_directory |
Required | Absolute path to the successfully published output bundle. |
index_file |
Required for the production JSON output | Logical bundle path index.json. |
normalized_output_count |
Required | Number of final normalized lane outputs returned by the pipeline. |
rejected_output_count |
Required | Number of recorded rejected outputs. |
warning_count |
Required | Number of final run warnings returned by the pipeline. |
validation_status |
Required | The run manifest's final validation status without reinterpretation. |
debug_directory |
Optional | Absolute debug-bundle path when debug capture was requested and completed. |
An illustrative successful result is:
{
"schema_version": "notarius.run-result.v1",
"run_id": "run-1770000000000000000-0123456789abcdef0123456789abcdef",
"pipeline_id": "dnd-session",
"output_directory": "/srv/narratio/runs/session-7/notarius/run-1770000000000000000-0123456789abcdef0123456789abcdef",
"index_file": "index.json",
"normalized_output_count": 6,
"rejected_output_count": 2,
"warning_count": 1,
"validation_status": "approved"
}
The receipt is a discovery and summary document, not a duplicate output
envelope. It does not embed lane payloads, rejection entries, warnings, the run
manifest, or output-file contents. Consumers use index_file and the existing
published JSON output contract for those records.
The result contract must tolerate future additive optional fields. Any incompatible field or semantic change requires a new run-result schema version.
Stream, Publication, And Failure Semantics
Machine-readable output is emitted only after:
- the pipeline has completed without a framework error;
- all logical output files have been successfully published;
- requested debug terminal reporting has completed; and
- all result fields are known.
Writing or encoding the machine-readable result is part of successful command completion. Failure to write it produces the existing runtime-failure exit class.
With --json:
- successful stdout is exclusively the run-result JSON document;
- successful warnings remain on stderr under the existing CLI contract;
- syntax and runtime errors retain their existing exit statuses and stderr diagnostics;
- consumers treat stdout as a valid result only when the process exits with status 0; failures before result writing emit no result, while a failure during the stdout write may leave incomplete bytes that must be ignored; and
- human-readable diagnostic wording is not promoted into a machine contract.
Without --json, current interactive stdout and stderr behavior remains
unchanged.
Successful runs may contain rejected outputs or omit some normalized lanes.
That remains a valid pipeline outcome. The run result reports counts, while
index.json, rejected.json, and warnings.json remain authoritative for
details. Notarius will not add a generic --fail-on-rejection policy as part
of this work.
Output Discovery And Consumer Responsibilities
The production JSON encoder's index.json remains the authoritative mapping
from lane IDs to published payloads. A subprocess consumer should:
- resolve
index_filebeneathoutput_directoryand reject path escape; - locate expected outputs by
lane_id, not by guessing filenames; - check each selected descriptor's media type and schema identity;
- decode payloads according to their published integration contracts;
- decide which lanes are required or optional for its own later stages; and
- retain rejection, warning, and manifest files when they are needed for provenance or review.
For Narratio, required report inputs and partial-success policy remain Narratio stage configuration and orchestration concerns. Notarius does not acquire knowledge of Narratio stages, manifests, workspace layout, publication policy, or report formats.
Invocation Guidance
The consumer documentation recommends that subprocess callers:
- use
notarius config validate --pipelineas an optional preflight; - pass explicit absolute paths for the input, configuration, output root, and CLI-supplied references;
- use a stable, non-secret prompt session identifier when useful for provider routing or caching;
- capture stdout and stderr separately;
- supply credentials through the configured environment mechanism rather than command arguments or generated configuration containing secret values;
- place output, cache, debug, and subprocess logs under intentional sensitivity and retention policies; and
- treat the Notarius manifest and run-result receipt as provenance while leaving the caller's own manifest authoritative for its stage lifecycle.
Notarius configuration remains owned by Notarius. An orchestrator may select a configuration and pass supported operational overrides, but should not duplicate the complete Notarius configuration schema.
Documentation End State
docs/cli.mdownsrun --json, stream behavior, and exit semantics;- a new
docs/integrations/run-result.mdowns the versioned run-result wire contract and compatibility policy; docs/integrations/json-output.mdremains the sole owner of output-bundle discovery and lane publication;- a new
docs/consumers/subprocess.mdprovides the task-oriented invocation and consumption workflow; and docs/internal/cli.mddescribes how the CLI constructs and emits the result only after successful publication.
Other documents should link to these owners instead of repeating volatile fields or command details.
Acceptance Criteria
- An ordinary successful
runretains its existing human-readable output. - A successful
run --jsonemits one validnotarius.run-result.v1document and no human prose on stdout. - Relative configured or overridden output and debug roots are reported as absolute bundle paths.
- The receipt identifies the production JSON bundle entry point without copying its lane descriptors or payloads.
- Warning-bearing and rejection-bearing runs remain successful and report accurate counts.
- Syntax, configuration, provider, pipeline, publication, debug, and result writing failures retain the correct nonzero exit class. Consumers are explicitly required to ignore stdout from a nonzero invocation.
- The implementation does not expose internal Go types or couple generic CLI code to D&D or Narratio concepts.
- Public and internal documentation assigns each new contract to one canonical owner.
- Offline behavioral tests protect the structured-output contract, default human behavior, absolute path reporting, stream separation, and failure to serialize or write the success result without duplicating lower-level output encoder tests.
Out Of Scope
The following may be useful later but are not prerequisites for the Narratio integration:
- a result-file flag in addition to machine-readable stdout;
- a JSON failure envelope or stable machine-readable error taxonomy;
- caller-supplied Notarius run IDs or exact output-bundle paths;
- a generic
--fail-on-rejectionor required-lane CLI policy; - a public Go client package or importable Narratio adapter;
- Narratio stage, configuration, manifest, or report-generation changes;
notarius version --json;- installable or queryable artifact JSON Schemas;
- signal-aware CLI contexts and graceful SIGINT or SIGTERM handling;
- packaged release artifacts and a broader application-versioning policy.
These items should be promoted only in response to a demonstrated integration need rather than bundled into the initial subprocess contract.