From 1960304f6fb815687df2cd94679e7b3df89e6f49 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 9 Nov 2026 17:33:30 +0000 Subject: [PATCH] Revise the companion input roadmap around main-derived contexts --- docs/roadmap/main-relative-inputs.md | 500 +++++++++++++++------------ 1 file changed, 272 insertions(+), 228 deletions(-) diff --git a/docs/roadmap/main-relative-inputs.md b/docs/roadmap/main-relative-inputs.md index 00f42c4..29a1dde 100644 --- a/docs/roadmap/main-relative-inputs.md +++ b/docs/roadmap/main-relative-inputs.md @@ -1,286 +1,330 @@ -# Main-relative underlays and overlays +# Main-relative companion imports and overlays -Status: accepted direction; API and filesystem-policy decisions remain open. -Not implemented. Planning baseline: `191015e`. +Status: accepted direction; public representation and remaining filesystem-policy +choices are open. Not implemented. Implementation baseline: `191015e`. ## Purpose -Allow an application to select its main configuration through ConfigKit's -existing discovery descriptions, then load explicitly declared underlay files -and a selected overlay relative to that main file. Applications should not need -to repeat discovery themselves or run a preliminary configuration load to learn -the selected directory. +Make the common workflow straightforward: discover the main configuration file, +load optional companion fragments beside it, and apply a selected native overlay +in one configuration load. Applications choose their conventions; operators can +drop resource definitions into the declared locations without adding import +boilerplate to the main file or creating a manifest on disk. -The application continues to choose its search conventions, underlay tiers, and -overlay name. ConfigKit resolves their filesystem relationship within the same -load. Independently located inputs remain useful and can be combined with -main-relative inputs. +The central addition is deferred filesystem-context binding for application-owned +underlay inputs, including `Mapping` and `Bytes` sources containing native import +declarations. Bind their imports to the selected main directory during loading. +Reuse existing optional-file, directory, recursion, pattern, destination, and +composition behavior. A new file constructor alone would not cover this workflow, +and a second fragment-discovery implementation is unnecessary. ## Current baseline -The [discovery contract](../config.md#configuration-discovery) resolves a -`SearchConfig` source inside loading. It selects one host file or absent input; -errors processing the selected file do not resume the search. The public -constructor returns a source description, not a selected filename. +The [discovery contract](../config.md#configuration-discovery) resolves +`SearchConfig` inside loading to one host file or absent input. Selected-file +failures do not resume discovery. The constructor returns a source description, +not a selected filename. -Ordinary `Load` already derives an overlay context from a selected file. Without -an explicit root override, selecting `/etc/example/config.yml` permits overlay -`production` to load from `/etc/example/overlays/production.yml`. Optional search -exhaustion supplies no inferred root; ordinary loading then needs an explicit -context for an active overlay. +Ordinary `Load` already infers overlay context from a file source. Without a +root override, `/srv/campaign/audita.yml` supplies the location +`/srv/campaign/overlays/production.yml` for overlay `production`. Existing overlay +lookup uses the configuration root, which can differ from the main directory. +Optional discovery exhaustion provides no inferred context. -The [layered API](../config.md#layered-loading) differs: +The [layered API](../config.md#layered-loading) has the coordination gap: -- An active overlay requires `LayeredOptions.OverlayFilesystem` independently of - the main source. Grouped preflight rejects its absence before discovery runs. -- `Underlay.Inputs` contains independently specified sources and contexts. A - file source can establish its own context, but no declaration binds an - underlay filename to the main file that discovery will select. -- Main acquisition already precedes underlay acquisition. Underlay groups are - subsequently composed from lowest to highest priority, beneath the main tier. -- Ordinary relative imports are peers of their declaring input. They do not - express lower-priority underlay tiers. +- An active overlay requires `LayeredOptions.OverlayFilesystem`. Preflight + rejects its absence before discovery runs. +- Underlay sources and contexts are supplied independently. Application-owned + mappings or bytes can already contain import declarations, but cannot obtain + their import context from the main file that discovery will select. +- Native imports already support optional named files and recursive directory + searches with filename filtering and placement. They compose as peers of + their declaring input, so putting declarations in an underlay gives them + underlay priority. Putting the same declarations in the main file does not. +- Main acquisition already precedes underlay acquisition. Existing composition + subsequently applies underlay groups from lowest to highest beneath the main. -The extension can therefore reuse the selected main's acquired filesystem -information and the existing grouped lifecycle. It needs a way to express the -relationship publicly and bind it before dependent acquisition. +This feature extends context selection and binding within that lifecycle. + +## Audita workflow + +Audita supplies the companion import declarations in application-owned mappings +or bytes. Their filesystem bases follow the selected main file, whether selected +explicitly or through ConfigKit's built-in searches. For a main file at +`/srv/campaign/audita.yml`, running from `/tmp` must not relocate these companions: + +| Resource | Application-declared locations | Role | +| --- | --- | --- | +| Glossaries | Optional `glossary.yml` and recursive `glossary/` | Underlay contributions mounted at `glossary_collections` using the appropriate existing destination and placement controls | +| Prompt definitions | Optional `prompts.yml` and recursive `prompts/` | Operator contributions above the bundled PromptKit catalog and Audita's embedded prompts | +| Selected native overlay | `overlays/.yml` | The one named overlay applied after main composition | + +Both resource-directory searches select `*.yml` and `*.yaml`. The file and +its corresponding directory contribute together if both exist; neither suppresses +the other. Each pair composes strictly as peers within its tier. Missing optional +resources contribute nothing; unreadable selected files, invalid definitions, +and composition conflicts remain errors. + +Prompt overrides rely on existing tier and identity rules. The operator prompt +tier sits above embedded prompt tiers, allowing whole-record upsert by registered +prompt ID under the applicable collection policy. Two operator fragments defining +the same ID in that tier conflict; filename ordering does not choose a winner. +The consuming application selects each fragment's schema and placement. + +This does not require combining Audita's and PromptKit's schemas. If PromptKit +uses a separate engine, its catalog load establishes the prompt tiers and can +use the selected main's recorded context after Audita's application load. That +is a separate domain load, not a preliminary load to repeat main discovery. +This feature's acceptance does not require changing another repository. + +The overlay directory is not imported wholesale as an underlay: its files are +alternative named configurations. No selection means no overlay. Selecting a +name retains the existing missing-selected-overlay error. An aggregate +`overlays.yml` would need its own named-definition and conflict rules and is +outside this feature; it is not a second spelling for current overlay lookup. ## Targeted end state -### Application declarations +### Companion underlays -An application can declare, before loading: +The application declares an underlay `Input` containing native imports and +selects main-derived filesystem binding for that input. `Mapping` and `Bytes` +are first-class supported sources for this use. Exact Go declarations remain +open in OD-1; no new operator-facing YAML syntax is needed. -1. A main `Input` using `SearchConfig`, with any supported combination of search - presets and custom candidates. -2. One or more underlay files whose paths are relative to the selected main - file's directory, grouped and ordered through the existing underlay API. -3. A selected overlay whose context is derived from the selected main file. +Once the main is selected, ConfigKit supplies the underlay import base from +that file's directory and binds the namespace and containment policy. Existing +import selection then acquires the companion files. Every imported file uses +its own directory for its further relative imports. For example, an import of +`extra.yml` from `glossary/terms.yml` resolves to `glossary/extra.yml`. -The relationship is explicit and declarative. It does not require a new -application callback, a second load, or a public intermediate configuration. -Exact API spelling and context selection are subject to OD-1. Missing-main -behavior, filesystem policy, and eligible main sources are subject to OD-2 -through OD-4; the examples below assume a successfully selected host file. +Applications choose underlay groups and their order. A group composes strictly; +separate groups establish precedence. Existing destinations, sequence placement, +source-version policies, and load-wide import defaults still apply. Binding a +context does not itself enable imports or change collection operations. -Existing input destinations, placement, import opt-in, and load-wide policies -remain applicable to underlay inputs. The new relationship determines where an -input is acquired; it does not change its precedence or composition rules. -An underlay's own relative imports continue to resolve from that underlay's -declaring directory. +The relationship is explicit on companion inputs. Independently located and +embedded inputs keep their own contexts and can coexist in the same load. +Providing a concrete context should select that complete context over derived +binding, without field-by-field fallback or recovery from an invalid explicit +context. OD-1 addresses how to represent those choices cleanly. -### Examples +There is no requirement to add a dedicated main-relative file constructor. +Optional named-file acquisition is already expressible through the underlay's +native imports. Ordinary `File` paths do not silently gain new relative semantics. -These describe intended behavior, not implemented Go syntax. Assume there is no -explicit configuration-root override and that the selected main file is: +### Layered overlays -```text -/etc/example/config.yml -``` +For an active layered overlay, use an explicit `OverlayFilesystem` when supplied. +Otherwise derive the overlay context automatically from the available main-file +information; the common workflow requires no `OverlayFromMain` flag. An invalid +explicit context fails rather than falling back. Inactive overlays need no +context. Missing-main and fallback cases are addressed below and in OD-2. -| Application declaration | Selected input | -| --- | --- | -| Main-relative underlay `defaults/base.yml` | `/etc/example/defaults/base.yml` | -| Main-relative underlay `defaults/site.yml` | `/etc/example/defaults/site.yml` | -| Main-relative overlay context, overlay name `production` | `/etc/example/overlays/production.yml` | +For this newly derived layered context, the lookup location is the main file's +directory, independently of a wider containment root. If the main is +`/srv/campaign/audita.yml` and its permitted root is `/srv`, the selected file +is `/srv/campaign/overlays/production.yml`, not `/srv/overlays/production.yml`. +Widening containment must not relocate the automatically selected companions. -If the underlays are placed in separate groups in that order, effective priority -is typed defaults, base underlay, site underlay, main, overlay, then CLI. -Putting both underlay inputs in one group instead composes them strictly as -peers. A declaration of `extras.yml` inside `defaults/base.yml` resolves beside -that file, at `/etc/example/defaults/extras.yml`. +Keep existing explicit-overlay-context lookup behavior and ordinary `Load` +behavior. The implementation must represent the derived lookup base separately +from its containment root where necessary, rather than simply copying today's +root-relative overlay context. Native overlay names, filenames, selection, +precedence, and validation retain their existing semantics. -If discovery instead selects a file in the user's configuration directory, the -same relative declarations follow that file's directory. An embedded or otherwise -independent underlay may coexist with these inputs and retains its own namespace -and context. No directory is searched for underlays merely because it exists. +### Absent main and optional companions -### Loading and inspection +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. -Resolve the main-relative descriptions using the selected main's acquired -filesystem information, before acquiring the inputs that depend on it. Keep -discovery within the existing single loading lifecycle and preserve main-first -acquisition, underlay tier order, version processing, selected-overlay timing, -and the existing defaults, resolution, secret, and validation phases. +Do not infer a directory from unsuccessful candidates or silently use the working +directory. An application may explicitly choose the working directory as its +fallback. An active selected overlay still needs a usable context and the selected +file; optional companion imports do not make that overlay optional. Independent +underlays and explicitly located overlays retain their absent-main behavior. +No fallback applies to a failure reading or processing an actually selected main. -Static declaration errors can still be checked before source acquisition; -checks that need the selected directory must run after it is available. The -implementation plan should identify this division without imposing a new global -ordering guarantee for unrelated diagnostics or filesystem checks. +### Lifecycle, evidence, and compatibility -After binding, use ordinary source acquisition, parsing, import handling, and -overlay loading. A missing required input, unreadable selected file, or invalid -configuration follows the applicable existing failure rules; it does not cause -main discovery to try another candidate. This feature does not itself introduce -optional-file syntax, underlay globbing, additional overlay filenames, or a new -overlay stack. +Bind dependent contexts after the main information is available and before +traversing their imports or loading the overlay. Preserve main-first acquisition, +underlay precedence, version processing, selected-overlay timing, and the existing +defaults, CLI, resolution, secret, and validation phases. No application context +callback, second discovery API, or preliminary full load is required. -Acquired files retain their actual source identity, path, source-local locations, -layer, underlay index, and passive resource context. Do not create an extra -source or precedence tier for the relative declaration itself. Preserve existing -namespace identity, repetition scope, shared acquisition budgets, detached -inspection, and resource cleanup. Use ordinary diagnostic classifications where -they fit; decide whether any new classification is needed during API design. +Check static declarations during preflight where possible; defer checks requiring +the selected directory. Do not introduce a global ordering guarantee for unrelated +diagnostics or filesystem checks. Selected-file and companion acquisition errors +remain terminal rather than restarting discovery. -### Compatibility and scope +Application-supplied mappings or bytes remain ordinary input sources with their +own labels, evidence, and existing validation obligations. Binding a context does +not manufacture a main document, exempt these inputs from source-version policy, +or give them a fabricated physical file path. Imported files retain their actual +source identity, locations, precedence layer, underlay index, and passive resource +context. Preserve namespace identity, repetition scope, shared budgets, detached +inspection, and acquisition-handle cleanup. -Preserve successful existing ordinary and layered loading behavior. Main-relative -selection should be additive and opt-in, with independently supplied sources and -contexts continuing to work. Preserve existing named-overlay lookup semantics; -OD-3 determines the root used by the new context selection. +Successful existing ordinary and explicitly configured layered loads should retain +their behavior. Automatically deriving a layered overlay context intentionally +relaxes the former missing-context error. Companion directory conventions are +selected by applications; ConfigKit does not universally scan `glossary/` or +`prompts/` without those declarations. -The work does not add general resource-path resolution, changes to process working -directory, remote acquisition, or a generic source-provider callback framework. -These are scope boundaries for this feature, not new architectural exclusions. -There is no new filesystem race-protection or sandbox guarantee. - -The design follows [ADR 0019](../adr/0019-explicit-configuration-discovery.md): -applications select conventions while ConfigKit performs selection and loading. -Review whether the finalized context-ownership decision needs an additional ADR; -do not rewrite an accepted ADR's decision content. No release version or new -release gate is selected by this roadmap. +This work adds no general resource-path resolver, remote acquisition, mutation of +the process working directory, filesystem race-protection guarantee, or general +source-provider callback framework. These are scope boundaries, not new permanent +architectural exclusions. The design follows +[ADR 0019](../adr/0019-explicit-configuration-discovery.md). Review ADR and policy +follow-up for deferred context ownership without rewriting accepted decisions. +No release version or additional release gate is selected here. ## Work from the baseline -1. **Settle the public declaration and filesystem policies.** Resolve the open - decisions below, document combinations with explicit contexts, and prepare - representative API examples. Keep public types owned by the root package. -2. **Represent the relationship through the facade and request preparation.** - Update the relevant declarations and conversions in `layered.go`, - `lifecycle.go`, or `source.go` as the selected API requires. Carry the intent - through the private request without prematurely interpreting paths against - the working directory. Preserve reusable-description and input-ownership - conventions. -3. **Bind dependent inputs during acquisition.** Extend the request preparation - and acquisition boundary in `internal/engine/load_request.go`, - `load_input.go`, and `acquisition.go`. Reuse discovery's selected concrete - source and filesystem-context resolution. Establish which checks remain in - preflight and which require resolved main information. -4. **Integrate underlays and overlays.** Resolve relative underlay files into - ordinary acquisitions with their own import bases; derive the selected - overlay context and reuse its loader. Preserve independent input contexts, - namespace handling, cleanup on failure, and source/error evidence. -5. **Verify observable behavior and update documentation.** Add focused public - coverage and maintained consumer examples, then update the discovery, - layered-loading, and selected-overlay contracts, declaration comments, and - relevant internal ownership documentation. Explain the difference between a - file's directory and the configured root when they differ. +1. **Finalize context declarations and absence policy.** Resolve the remaining + choices below and prepare Go examples for Audita's mapping/bytes workflow, + explicit context overrides, and independently located embedded inputs. +2. **Carry binding intent through the public facade and load request.** Update + the relevant input/options declarations and conversions in `layered.go` and + `lifecycle.go`, retaining root-owned public types and normal ownership rules. + Distinguish a deferred relationship from a concrete filesystem context. +3. **Bind underlay import contexts after main selection.** Extend preparation + and acquisition in `internal/engine/load_request.go`, `load_input.go`, and + `acquisition.go` as needed. Reuse the acquired main's directory and namespace, + apply the chosen missing-base policy, and delegate selection to existing import + machinery. Preserve independently supplied contexts. +4. **Derive overlay context and separate lookup from containment.** Remove the + unconditional explicit-context requirement for the new layered default. + Preserve explicit and ordinary lookup while enabling a main-directory lookup + base inside a potentially wider root. Reuse selected-overlay loading and its + failure and resource-ownership behavior. +5. **Verify the complete workflow and document it.** Add maintained consumer + examples, public integration coverage, and focused engine tests. Update the + discovery, layered-loading, import-context, and selected-overlay contracts, + declaration comments, and internal ownership documentation when implemented. This is dependency order for a later implementation plan, not a required commit -layout or a requirement to expose intermediate stages to consumers. Reuse the -existing lifecycle; a new discovery pass or a second configuration load is not -needed. +layout or a requirement to expose intermediate stages to consumers. ## Validation and completion -Exercise the behavior through the public API, supported by focused engine tests: +Validate behavior through the public loading boundary, including: -- Main discovery selects an early or later candidate; the dependent files follow - the actual selection, including when it is outside the working directory. -- Relative and independent underlays coexist; multiple groups retain precedence, - and peers in one group retain strict-composition conflicts. -- Underlay imports use their own file's directory. Placement and source-version - policies remain effective after binding. -- Active and inactive overlays, explicit contexts, optional search exhaustion, - and required-search failures follow the settled policies. -- Symlinked main files, explicit root overrides, parent-relative paths, and - namespace boundaries follow OD-3 and OD-4 without broadening existing access - guarantees. -- Selected-file failures and dependent acquisition failures are terminal; no - repeated full load or duplicate defaults/resolution/validation callbacks are - introduced. -- Source records, underlay indexes, origins, passive contexts, and failed-load - evidence identify the actual acquired inputs. Existing handle cleanup and - budget accounting still cover dependent acquisitions. -- Existing ordinary discovery and overlay loading, independent layered inputs, - and reuse of descriptions across loads retain their behavior. +- Explicit and discovered main files, early and later search candidates, and an + unrelated invocation directory. Companions follow the same selected main. +- Mapping and bytes underlays containing optional named-file and recursive + directory imports with `*.yml`/`*.yaml` filtering and mounted destinations. +- File only, directory only, both, neither, empty directories, and invalid or + unreadable selected fragments. Both forms compose as peers when present. +- Operator prompt overrides above embedded catalogs using registered identity; + same-tier duplicate IDs remain conflicts. Main and overlay precedence survive. +- Mixed embedded and companion inputs, multiple underlay tiers, transitive + imports, placement, source-version checks, and load-wide import defaults. +- Automatic derived overlays and explicit overrides, active and inactive names, + broader containment roots, and missing selected overlays. +- Optional discovery exhaustion, required discovery, fallback and skip policies, + mixed payload/required-import cases from OD-2, and terminal selected-main errors. +- Symlinks, eligible namespaces, parent-relative paths within the selected scope, + context validity, and namespace identity under OD-3 and OD-4. +- Normal source evidence, diagnostics, passive resource contexts, cleanup, and + budget accounting; no duplicate lifecycle callbacks or preliminary full load. +- Existing ordinary and explicit layered workflows and description reuse. -Run focused checks during implementation and the repository's applicable normal -checks before completion. No benchmark campaign or additional release gate is -required for this feature. Completion means applications can demonstrate the -discovery-plus-relative-input workflow in one load, with documented public -declarations and verified failure behavior. +Run focused checks during implementation and applicable normal repository checks +before completion. No benchmark campaign is required. Completion means the +application can discover its main, bind companion imports and the selected +overlay, and receive normal resolved configuration and inspection in one load, +without an application directory walker, parser, or extra discovery pass. ## Open Decisions -### OD-1: Public declaration shape and explicit-context combinations +### OD-1: Public representation of deferred context binding -**Recommendation:** add declarative, explicit choices for a main-relative -underlay file and a main-derived overlay context. A dedicated underlay source -constructor and a small overlay context-selection option are plausible shapes; -names remain to be chosen. Keep the existing independent-source/context path as -the default. For overlays, an explicitly supplied `OverlayFilesystem` should -take precedence over a request to derive context, allowing application overrides -without changing shared setup. Specify analogous precedence for any permitted -underlay context overrides. This keeps common use short without making nil -contexts change meaning or introducing callback lifetime concerns. +**Settled:** companion `Mapping` and `Bytes` inputs must work; native imports own +fragment selection. Layered overlays derive automatically when no explicit +context is supplied. Concrete contexts override derivation as a whole. -**Alternative:** add a general deferred filesystem-context descriptor shared by -inputs and overlays. This could give context selection one uniform representation -and accommodate later relationships, but risks expanding a small feature into -a general context API. It is attractive if concrete API sketches show less -duplication than separate declarations. Rejecting simultaneous explicit and -derived overlay choices is also viable: it catches ambiguous setup, but requires -callers to clear the derived choice when supplying an override. +**Recommendation:** represent main-derived context as a small declarative choice +on an underlay `Input`, with a helper or constructor for the common case. Preserve +its existing source, placement, import enablement, and tier. If both binding intent +and `Input.Filesystem` are supplied, use the concrete context without merging +fields. This is appropriate for mapping/bytes inputs because their context owns +import resolution; it does not reinterpret a file source's own path. Include the +absent-main policy from OD-2 in the binding description. Exact names and shape +need an API sketch, but no callback or second file-selection API is necessary. -### OD-2: No main file is selected +**Alternative:** introduce a shared context-selection descriptor for both inputs +and overlays, representing explicit, main-derived, and fallback contexts. This +could make the choices more uniform, particularly as fallback policy grows, but +adds a wider abstraction and must coexist with today's concrete context fields. +Rejecting simultaneous concrete and derived choices is viable but requires +callers to clear shared setup when providing an explicit override. -**Recommendation:** when an active dependent declaration needs a main-file base -and none exists, fail with a clear diagnostic. Do not use an attempted candidate -directory or the working directory as an implicit substitute. This makes an -unresolvable relationship explicit without making discovery globally required. -Applications can require the main search or use independent inputs and an -explicit overlay context when absent-main operation is intended. Inactive -overlays do not require a derived context. +### OD-2: Scope and representation of absent-main handling -**Alternative:** treat main-relative inputs as conditional on main presence and -skip them after optional exhaustion. This supports defaults-only startup and is -consistent with a permissive search, but could silently omit an explicitly -selected overlay or expected underlay. A selectable skip policy could support -that use case, at the cost of another option; adopting it would require defining -its effect on tier evidence and distinguishing absent main from a missing file -beside an existing main. +**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. -### OD-3: Relative base, configuration root, and symlinks +**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. -**Recommendation:** anchor underlay filenames to the canonical selected main -file's directory, consistent with existing file/import behavior. Derive overlay -context from the main's resolved context, so overlay lookup remains relative to -its configuration root. When an explicit main root is wider than the main -directory, underlay filenames still use the directory as their base and overlays -use that root. Inherit the main's root for dependent underlay acquisition and -imports unless an explicitly supported context override selects another root. -Each acquired underlay supplies its own import base. Apply existing canonical -containment checks; allow parent-relative traversal when it stays within the -selected root rather than adding a blanket prohibition on `..`. +**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. -This distinguishes lookup from containment, reuses existing machinery, and -supports sibling directories under an explicitly wider root. It also means a -symlinked main selects resources beside its target, which must be documented. +### OD-3: Containment inheritance and symlink convention -**Alternative:** always create a fresh root at the main file's directory for -both kinds of input. This makes every main-relative lookup visually local, -including with a wider main root, but discards intentional root configuration -and prevents some sibling-directory layouts. Using the main file's lexical -symlink directory instead is another viable convention for deployment bundles; -it would differ from current canonical import behavior and require separate -handling for lookup and containment. +**Settled:** derived companion imports and derived layered overlays use the main +file's directory for lookup, even with a wider configured containment root. +Explicit overlay contexts retain their current lookup semantics. -### OD-4: Eligible main sources and namespaces +**Recommendation:** use the selected main's canonical directory, and inherit its +resolved namespace and containment root for derived bindings. Existing import +rules then provide file-local bases for transitive imports. Permit parent-relative +paths when existing containment rules allow them. This reuses current canonical +file behavior and preserves intentional wider roots without relocating companions. +A concrete underlay context override can select a different scope under its +normal rules. Document the symlink-target-directory convention explicitly. -**Recommendation:** support discovered and explicit host files, and native -`Filesystem.File` mains, using each namespace's existing path rules and resource -ownership. Discovery currently selects host files; a native file should not -require discovery merely to provide the same directory relationship. Bind paths -within the selected namespace and reuse its identity. For this initial feature, -byte, reader, mapping, and absent mains do not supply a main-file directory; -independently specified contexts remain available for those workflows. +**Alternative:** create a fresh containment root at the selected main directory. +This keeps companions locally scoped but discards intentional wider roots and +prevents some sibling-directory layouts. Anchoring to the lexical symlink directory +is also viable for deployment bundles; it differs from current file/import +behavior and would need distinct lookup and containment handling. -**Alternative:** derive from any resolved main filesystem context, including an -explicit `BaseDir` for non-file inputs. This is more uniform for context-based -loading and avoids an artificial file requirement when a base is already known, -but changes the concept from relative-to-main-file to relative-to-main-context. -It needs explicit rules for absent mains and root-only contexts, where root and -base are not interchangeable. Limiting the first implementation to host files -is also viable and smaller, but would leave native-filesystem consumers with -the same coordination gap. +### OD-4: Main-source eligibility beyond discovered host files + +**Settled:** both explicitly selected and discovered host mains support the +workflow. Non-file companion inputs, especially mappings and bytes, are in scope; +this decision concerns the main input that supplies their base. + +**Recommendation:** also support native `Filesystem.File` mains using their +namespace's path and ownership rules. For an initial file-based scope, non-file +mains use independently supplied or fallback contexts rather than implicitly +providing a main-file directory. This covers the requested workflow and avoids +making discovery a prerequisite for equivalent file inputs. + +**Alternative:** derive from any usable main context, including `BaseDir` on a +byte, reader, or mapping main. This is more uniform with context-based loading +and avoids excluding a known base, but requires explaining main-relative as +main-context-relative and deciding how root-only or absent-main contexts behave. +A host-only initial scope is smaller but leaves native-file consumers with the +same coordination gap.