|
Bootstrap
Bash-based bootstrap engine reference documentation
|
Accepted
This ADR records the intended command-line and execution semantics for processing multiple manifest files in one Bootstrap invocation.
The decision is intentionally described in detail because error handling is part of Bootstrap's public safety contract. Future implementation work should preserve both the selected behavior and the reasoning behind it rather than treating multiple-manifest support as a simple argument-parsing convenience.
Bootstrap currently accepts one manifest file per invocation. Users who divide their desired packages into focused manifests, such as core, containers, security, or language-specific manifests, must invoke Bootstrap repeatedly.
A natural command-line extension is to accept multiple manifest paths:
Shell glob expansion should also work without Bootstrap implementing its own file discovery:
Concatenating files before passing them to Bootstrap is not an equivalent solution:
When standard input is used, the parser sees - as the input source. An error can therefore be reported only against that synthetic source and its combined line number. The diagnostic cannot reliably identify which original file contained the error or which line number applied within that file.
Human-friendly diagnostics are a central benefit of Bootstrap. Errors should identify the actual manifest path and original line number whenever that information is available. Multiple-manifest support must preserve that provenance through parsing, planning, resolution, explanation, and reporting.
The initial discussion considered behavior similar to invoking Bootstrap once per file. That approach preserves provenance, but a direct sequence such as:
would execute the first manifest before the second manifest had been parsed or planned. A malformed later manifest could therefore be discovered only after an earlier manifest had already modified the system.
The preferred model is stronger. Bootstrap should first preflight the complete set of supplied manifests. Execution should begin only when every unignored error condition has been resolved successfully.
The discussion also identified a legitimate future need for explicitly permissive modes. A user may prefer to report and skip an individual package failure or abandon one failed manifest while continuing with other manifests. Those behaviors should be possible only through explicit command-line options. They must not weaken Bootstrap's conservative default.
The decision is guided by the following concerns:
Bootstrap shall accept one or more manifest operands in a single invocation.
Each manifest shall retain its own source identity. Records and diagnostics produced from a manifest shall preserve the original manifest path and line number throughout the pipeline.
Bootstrap shall process multiple manifests using two broad phases:
Preflight includes, at minimum:
By default, the first error encountered during preflight shall stop the run. Bootstrap shall execute no actions from any supplied manifest when an unignored preflight error occurs.
If every supplied manifest completes preflight successfully, Bootstrap shall execute the resulting resolved actions in manifest argument order and in the established action order within each manifest.
The default behavior is therefore conceptually:
It is deliberately safer than either concatenating the manifests or invoking Bootstrap independently for each file.
Operational options such as --dry-run, --explain, --verbose, --quiet, and --package-manager shall apply to the complete invocation and therefore to every supplied manifest.
Manifest paths shall be processed in the order received from the shell. Bootstrap shall not implement implicit manifest discovery or reorder operands.
The - operand shall continue to represent standard input.
Because standard input cannot normally be replayed and has no original file identity, at most one - operand should be accepted in one invocation. Its source shall remain -, and diagnostics shall use line numbers from that input stream.
Users who require original filename provenance should supply manifest paths rather than concatenate files into standard input.
Without an explicit continuation option, any error shall stop processing and prevent execution.
This includes errors associated with:
Execution failures necessarily occur after the preflight barrier. By default, an execution failure shall stop further execution and cause the overall run to fail.
Future or accompanying CLI work may provide two independent continuation policies:
These names are preferred over --ignore-* forms because the errors are not ignored. Bootstrap still explains, records, and reports them. The option changes whether the error halts subsequent work.
The precise spelling remains part of the CLI design and may be refined before implementation, but the semantic separation is architectural.
When package-level continuation is enabled, a failure attributable to one package may be reported and skipped while Bootstrap continues processing other eligible packages.
Package-level failures may arise during parsing, planning, resolution, or execution. An implementation shall distinguish failures that can be safely isolated to one package from failures that invalidate the enclosing manifest or runtime state.
A package-level option shall not require Bootstrap to guess the intended meaning of malformed or ambiguous input. If a failure cannot be safely isolated to one package record, it remains a manifest-level or run-level failure.
When manifest-level continuation is enabled, a failure that invalidates one manifest may be reported, that manifest may be excluded from execution, and preflight may continue with later manifests.
Successful manifests may become eligible for execution only after preflight has completed for the full invocation and no remaining unignored run-level failure exists.
Manifest-level continuation shall not merge a failed manifest's partial plan with executable plans from successful manifests.
When both continuation policies are enabled:
The hierarchy is:
Each continuation policy relaxes failure handling only at its stated level.
Continuation does not convert an incomplete run into complete success.
If any package or manifest error occurred, the overall command should return a nonzero status even when an explicit continuation option allowed additional work to proceed.
The final exit-code mapping may be specified separately, but callers must be able to distinguish:
A future explicit option could request success status for acknowledged skipped errors, but that behavior is not part of this decision and shall not be implied by continuation alone.
Diagnostics shall remain human-readable and shall identify the narrowest useful scope available:
Dry-run and explain modes should make the global preflight boundary visible. They should distinguish actions by source manifest and explain that execution was either prohibited or intentionally omitted.
Bootstrap could retain the existing one-manifest CLI and require users to invoke it repeatedly.
This preserves the current implementation and provenance behavior, but it creates repetitive command lines and does not provide a global preflight safety barrier across a related manifest set.
Bootstrap or the user could concatenate all input files and process the result as one logical manifest.
This is mechanically simple and permits one parser invocation. It was rejected because it loses or complicates original source provenance. Error messages may refer only to -, a temporary combined file, or a combined line number that is not directly useful to the user.
Concatenation also blurs manifest boundaries, making file-level continuation and reporting difficult.
Bootstrap could loop over manifest operands and run the existing complete pipeline for each one before moving to the next.
This preserves filenames and line numbers and may require relatively little orchestration work. It was rejected as the default because an early manifest could modify the system before a later manifest's parse, planning, or resolution failure was discovered.
Bootstrap could establish a global barrier after parsing and planning while deferring package-manager resolution until each manifest is about to execute.
This reduces retained preflight state, but it allows a later resolution error to be discovered after earlier execution has begun. Resolution is therefore part of preflight for this decision.
Bootstrap could preserve source metadata while combining every manifest's Action Records into a single plan and resolved action stream.
This may simplify global optimization or duplicate elimination. It was not selected as the required model because merging can obscure manifest boundaries, complicate manifest-level continuation, and introduce policy questions about cross-file ordering and duplicate requirements.
An implementation may use a combined internal stream only if source provenance, manifest boundaries, deterministic ordering, and continuation semantics remain fully preserved.
Bootstrap could report errors and continue by default.
This was rejected because partial provisioning can be difficult to detect and may leave a system in an unexpected state. Conservative fail-fast behavior remains the default.
Bootstrap could return status zero whenever it completed all work that remained after skipped failures.
This was rejected because automation would be unable to distinguish a complete bootstrap from a partial one. Continued work and successful work are not the same outcome.
A single option could permit all failures to be skipped when possible.
This is convenient but too broad. Package-level and manifest-level failures have different safety boundaries and consequences. Separate policies make user intent more explicit and reduce surprising behavior.
The intended design should extend the existing layered pipeline rather than replace it.
Likely implementation work includes:
Package-level continuation may require deeper parser, planner, resolver, or executor changes than basic multiple-manifest support. It may therefore be implemented after the global preflight and manifest-level behavior, provided the public design remains consistent with this ADR.
The following details require additional design or implementation validation:
These questions do not change the central decision: preserve provenance, preflight the complete invocation before execution, fail conservatively by default, and require explicit policy for partial progress.