From 2ba61d5c7c872c8d1c6bb0608847c9945ecde43e Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 9 Nov 2026 17:49:08 +0000 Subject: [PATCH] Settle absent-main behavior for companion inputs --- docs/roadmap/main-relative-inputs.md | 85 ++++++++++++++++------------ 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/docs/roadmap/main-relative-inputs.md b/docs/roadmap/main-relative-inputs.md index c9cfd5a..2c778fe 100644 --- a/docs/roadmap/main-relative-inputs.md +++ b/docs/roadmap/main-relative-inputs.md @@ -1,7 +1,7 @@ # Main-relative companion imports and overlays -Status: accepted direction and public API structure; absent-main and remaining -filesystem-policy choices are open. Not implemented. Implementation baseline: +Status: accepted direction, public API structure, and absent-main behavior; +containment and main-source eligibility remain open. Not implemented. Baseline: `191015e`. ## Purpose @@ -138,11 +138,11 @@ precedence, and validation retain their existing semantics. ### Absent main and optional companions Optional discovery may find no main file while defaults and CLI settings still -permit a successful application load. Support a declared absent-main policy for -dependent companion imports. Skipping optional companions is the intended default -for this workflow; applications can instead require a base or supply an explicit -fallback directory/context. The representation and exact skip scope remain in -OD-2, including inputs with required imports or additional application payload. +permit a successful application load. When no usable base is available, skip +optional companion import expansion while retaining the declaring input's +ordinary payload and validation. Required imports still fail. Applications can +require a base or supply an explicit fallback context on each derived binding. +OD-2 records the settled precedence, skip scope, and fallback behavior. Do not infer a directory from unsuccessful candidates or silently use the working directory. An application may explicitly choose the working directory as its @@ -249,14 +249,14 @@ without an application directory walker, parser, or extra discovery pass. Add a small, optional main-relative binding description to `Input`, retaining the concrete `Input.Filesystem` field. A helper supplies the common default -description; explicit settings group any absent-main controls decided in OD-2. +description; explicit settings group the absent-main controls settled in OD-2. Companion `Mapping` and `Bytes` inputs use native imports for fragment selection. Preserve the input's source, placement, import enablement, and tier. The proposed shape is an `Input.MainRelative` field of type `*MainRelativeContext`, with a `MainRelative()` convenience helper. These names -illustrate the settled structure; final spelling and OD-2's settings can be -finished during API design. For example, this unimplemented API sketch assumes +illustrate the settled structure; final spelling can be finished during API +design. For example, this unimplemented API sketch assumes `companionDeclarations` contains ordinary native import declarations: ```go @@ -275,7 +275,7 @@ setup without clearing its binding declaration. Layered overlays derive automatically when `OverlayFilesystem` is absent; no additional opt-in flag is needed. An explicit overlay context wins as a whole. -If OD-2 calls for configurable overlay fallback behavior, reuse the small binding +Support an explicit overlay fallback under OD-2, reusing the small binding settings where appropriate without requiring a general context-selection API. Keep the binding on `Input`: `Source` still describes the supplied content and @@ -285,32 +285,47 @@ a boolean and sibling fields, while keeping the addition smaller than a general context selector. No source wrapper, deferred fields on `FilesystemContext`, callback, or second file-selection API is needed for this design. +### OD-2: Scope and representation of absent-main handling — settled + +Put absence behavior on each derived binding. When no usable base exists, the +default skips optional companion import expansion, retaining the declaring +input's ordinary configuration values. Required imports produce an error; +requiredness includes applicable application import defaults. Continue normal +input and directive validation, so absence does not excuse invalid declarations. +This preserves independent payload and existing required/optional distinctions +without treating the entire input as conditional on main presence. + +Support a concrete fallback context and a require-base option within the binding +description. Illustrative fields are `Fallback *FilesystemContext` and +`RequireBase bool`; final spelling remains an API design detail. Select the +context in this order: + +1. A supplied `Input.Filesystem` is the complete override. +2. Otherwise, use a usable main-derived context. +3. Otherwise, use the explicitly supplied fallback context, if any. +4. Without any usable context, skip optional imports unless the binding requires + a base. A require-base binding or required import produces an error. + +A fallback can satisfy require-base: the option requires a usable context, not +an actual main file. Consumers requiring a main file can make discovery required. +An invalid selected context fails; it does not activate a lower-priority choice. +Fallback applies only when the main cannot provide a base, never after a failure +reading or processing a selected main, or after missing or invalid companion +files beside an existing main. Once bound, normal import selection and failure +rules apply. Do not guess from unsuccessful discovery candidates or implicitly +use the working directory; applications may explicitly choose it as a fallback. + +A fallback uses `FilesystemContext.BaseDir` as its lookup directory, with `Root` +and `FS` retaining their containment and namespace roles. This also applies to +the new overlay fallback: look for `overlays/.yml` beneath its base, while +preserving existing explicit `OverlayFilesystem` lookup behavior. An explicit +overlay context wins, followed by main derivation, then the declared overlay +fallback. When no overlay is selected, no overlay context is needed. An active +selection requires a usable context and the named file; never silently skip it. +Companion absence settings do not make a selected overlay optional. + ## Open Decisions -### OD-2: Scope and representation of absent-main handling - -**Settled:** optional companions should support defaults-only startup; a declared -fallback is useful, and guessed candidate directories or implicit working-directory -fallback are inappropriate. Selected-main failures remain terminal. - -**Recommendation:** put absence behavior on each derived binding. Default to -skipping optional companion import expansion when no main base exists. Provide -an explicit require-base choice and a concrete fallback context; use a fallback -only when no main base is available, never to recover from a selected-file error. -Keep any independent payload in the underlay input, and do not silently waive -required import declarations. A supplied fallback for the overlay can likewise -provide its lookup base; an active overlay without any usable context fails. -This preserves useful absent-main behavior without silently discarding unrelated -configuration or conflating required imports with optional ones. Finalize how -these choices are represented and how a fallback declares lookup base and root. - -**Alternative:** scope skip to the entire explicitly designated companion input. -This is simpler for the import-only mappings Audita describes and avoids partial -input processing, but also omits any payload or required imports in that input. -It needs clear semantics for that deliberate condition. A single load-wide -absence policy is another viable convenience, but cannot express different -requirements for separate companion inputs as directly. - ### OD-3: Containment inheritance and symlink convention **Settled:** derived companion imports and derived layered overlays use the main