Revise the companion input roadmap around main-derived contexts

This commit is contained in:
2026-11-09 17:33:30 +00:00
parent 26ea24958c
commit 1960304f6f

View File

@@ -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. Status: accepted direction; public representation and remaining filesystem-policy
Not implemented. Planning baseline: `191015e`. choices are open. Not implemented. Implementation baseline: `191015e`.
## Purpose ## Purpose
Allow an application to select its main configuration through ConfigKit's Make the common workflow straightforward: discover the main configuration file,
existing discovery descriptions, then load explicitly declared underlay files load optional companion fragments beside it, and apply a selected native overlay
and a selected overlay relative to that main file. Applications should not need in one configuration load. Applications choose their conventions; operators can
to repeat discovery themselves or run a preliminary configuration load to learn drop resource definitions into the declared locations without adding import
the selected directory. boilerplate to the main file or creating a manifest on disk.
The application continues to choose its search conventions, underlay tiers, and The central addition is deferred filesystem-context binding for application-owned
overlay name. ConfigKit resolves their filesystem relationship within the same underlay inputs, including `Mapping` and `Bytes` sources containing native import
load. Independently located inputs remain useful and can be combined with declarations. Bind their imports to the selected main directory during loading.
main-relative inputs. 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 ## Current baseline
The [discovery contract](../config.md#configuration-discovery) resolves a The [discovery contract](../config.md#configuration-discovery) resolves
`SearchConfig` source inside loading. It selects one host file or absent input; `SearchConfig` inside loading to one host file or absent input. Selected-file
errors processing the selected file do not resume the search. The public failures do not resume discovery. The constructor returns a source description,
constructor returns a source description, not a selected filename. not a selected filename.
Ordinary `Load` already derives an overlay context from a selected file. Without Ordinary `Load` already infers overlay context from a file source. Without a
an explicit root override, selecting `/etc/example/config.yml` permits overlay root override, `/srv/campaign/audita.yml` supplies the location
`production` to load from `/etc/example/overlays/production.yml`. Optional search `/srv/campaign/overlays/production.yml` for overlay `production`. Existing overlay
exhaustion supplies no inferred root; ordinary loading then needs an explicit lookup uses the configuration root, which can differ from the main directory.
context for an active overlay. 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 - An active overlay requires `LayeredOptions.OverlayFilesystem`. Preflight
the main source. Grouped preflight rejects its absence before discovery runs. rejects its absence before discovery runs.
- `Underlay.Inputs` contains independently specified sources and contexts. A - Underlay sources and contexts are supplied independently. Application-owned
file source can establish its own context, but no declaration binds an mappings or bytes can already contain import declarations, but cannot obtain
underlay filename to the main file that discovery will select. their import context from the main file that discovery will select.
- Main acquisition already precedes underlay acquisition. Underlay groups are - Native imports already support optional named files and recursive directory
subsequently composed from lowest to highest priority, beneath the main tier. searches with filename filtering and placement. They compose as peers of
- Ordinary relative imports are peers of their declaring input. They do not their declaring input, so putting declarations in an underlay gives them
express lower-priority underlay tiers. 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 This feature extends context selection and binding within that lifecycle.
information and the existing grouped lifecycle. It needs a way to express the
relationship publicly and bind it before dependent acquisition. ## 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/<name>.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 ## 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 Once the main is selected, ConfigKit supplies the underlay import base from
presets and custom candidates. that file's directory and binds the namespace and containment policy. Existing
2. One or more underlay files whose paths are relative to the selected main import selection then acquires the companion files. Every imported file uses
file's directory, grouped and ordered through the existing underlay API. its own directory for its further relative imports. For example, an import of
3. A selected overlay whose context is derived from the selected main file. `extra.yml` from `glossary/terms.yml` resolves to `glossary/extra.yml`.
The relationship is explicit and declarative. It does not require a new Applications choose underlay groups and their order. A group composes strictly;
application callback, a second load, or a public intermediate configuration. separate groups establish precedence. Existing destinations, sequence placement,
Exact API spelling and context selection are subject to OD-1. Missing-main source-version policies, and load-wide import defaults still apply. Binding a
behavior, filesystem policy, and eligible main sources are subject to OD-2 context does not itself enable imports or change collection operations.
through OD-4; the examples below assume a successfully selected host file.
Existing input destinations, placement, import opt-in, and load-wide policies The relationship is explicit on companion inputs. Independently located and
remain applicable to underlay inputs. The new relationship determines where an embedded inputs keep their own contexts and can coexist in the same load.
input is acquired; it does not change its precedence or composition rules. Providing a concrete context should select that complete context over derived
An underlay's own relative imports continue to resolve from that underlay's binding, without field-by-field fallback or recovery from an invalid explicit
declaring directory. 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 ### Layered overlays
explicit configuration-root override and that the selected main file is:
```text For an active layered overlay, use an explicit `OverlayFilesystem` when supplied.
/etc/example/config.yml 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 | 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
| Main-relative underlay `defaults/base.yml` | `/etc/example/defaults/base.yml` | `/srv/campaign/audita.yml` and its permitted root is `/srv`, the selected file
| Main-relative underlay `defaults/site.yml` | `/etc/example/defaults/site.yml` | is `/srv/campaign/overlays/production.yml`, not `/srv/overlays/production.yml`.
| Main-relative overlay context, overlay name `production` | `/etc/example/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 Keep existing explicit-overlay-context lookup behavior and ordinary `Load`
is typed defaults, base underlay, site underlay, main, overlay, then CLI. behavior. The implementation must represent the derived lookup base separately
Putting both underlay inputs in one group instead composes them strictly as from its containment root where necessary, rather than simply copying today's
peers. A declaration of `extras.yml` inside `defaults/base.yml` resolves beside root-relative overlay context. Native overlay names, filenames, selection,
that file, at `/etc/example/defaults/extras.yml`. precedence, and validation retain their existing semantics.
If discovery instead selects a file in the user's configuration directory, the ### Absent main and optional companions
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.
### 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 Do not infer a directory from unsuccessful candidates or silently use the working
filesystem information, before acquiring the inputs that depend on it. Keep directory. An application may explicitly choose the working directory as its
discovery within the existing single loading lifecycle and preserve main-first fallback. An active selected overlay still needs a usable context and the selected
acquisition, underlay tier order, version processing, selected-overlay timing, file; optional companion imports do not make that overlay optional. Independent
and the existing defaults, resolution, secret, and validation phases. 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; ### Lifecycle, evidence, and compatibility
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.
After binding, use ordinary source acquisition, parsing, import handling, and Bind dependent contexts after the main information is available and before
overlay loading. A missing required input, unreadable selected file, or invalid traversing their imports or loading the overlay. Preserve main-first acquisition,
configuration follows the applicable existing failure rules; it does not cause underlay precedence, version processing, selected-overlay timing, and the existing
main discovery to try another candidate. This feature does not itself introduce defaults, CLI, resolution, secret, and validation phases. No application context
optional-file syntax, underlay globbing, additional overlay filenames, or a new callback, second discovery API, or preliminary full load is required.
overlay stack.
Acquired files retain their actual source identity, path, source-local locations, Check static declarations during preflight where possible; defer checks requiring
layer, underlay index, and passive resource context. Do not create an extra the selected directory. Do not introduce a global ordering guarantee for unrelated
source or precedence tier for the relative declaration itself. Preserve existing diagnostics or filesystem checks. Selected-file and companion acquisition errors
namespace identity, repetition scope, shared acquisition budgets, detached remain terminal rather than restarting discovery.
inspection, and resource cleanup. Use ordinary diagnostic classifications where
they fit; decide whether any new classification is needed during API design.
### 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 Successful existing ordinary and explicitly configured layered loads should retain
selection should be additive and opt-in, with independently supplied sources and their behavior. Automatically deriving a layered overlay context intentionally
contexts continuing to work. Preserve existing named-overlay lookup semantics; relaxes the former missing-context error. Companion directory conventions are
OD-3 determines the root used by the new context selection. 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 This work adds no general resource-path resolver, remote acquisition, mutation of
directory, remote acquisition, or a generic source-provider callback framework. the process working directory, filesystem race-protection guarantee, or general
These are scope boundaries for this feature, not new architectural exclusions. source-provider callback framework. These are scope boundaries, not new permanent
There is no new filesystem race-protection or sandbox guarantee. architectural exclusions. The design follows
[ADR 0019](../adr/0019-explicit-configuration-discovery.md). Review ADR and policy
The design follows [ADR 0019](../adr/0019-explicit-configuration-discovery.md): follow-up for deferred context ownership without rewriting accepted decisions.
applications select conventions while ConfigKit performs selection and loading. No release version or additional release gate is selected here.
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.
## Work from the baseline ## Work from the baseline
1. **Settle the public declaration and filesystem policies.** Resolve the open 1. **Finalize context declarations and absence policy.** Resolve the remaining
decisions below, document combinations with explicit contexts, and prepare choices below and prepare Go examples for Audita's mapping/bytes workflow,
representative API examples. Keep public types owned by the root package. explicit context overrides, and independently located embedded inputs.
2. **Represent the relationship through the facade and request preparation.** 2. **Carry binding intent through the public facade and load request.** Update
Update the relevant declarations and conversions in `layered.go`, the relevant input/options declarations and conversions in `layered.go` and
`lifecycle.go`, or `source.go` as the selected API requires. Carry the intent `lifecycle.go`, retaining root-owned public types and normal ownership rules.
through the private request without prematurely interpreting paths against Distinguish a deferred relationship from a concrete filesystem context.
the working directory. Preserve reusable-description and input-ownership 3. **Bind underlay import contexts after main selection.** Extend preparation
conventions. and acquisition in `internal/engine/load_request.go`, `load_input.go`, and
3. **Bind dependent inputs during acquisition.** Extend the request preparation `acquisition.go` as needed. Reuse the acquired main's directory and namespace,
and acquisition boundary in `internal/engine/load_request.go`, apply the chosen missing-base policy, and delegate selection to existing import
`load_input.go`, and `acquisition.go`. Reuse discovery's selected concrete machinery. Preserve independently supplied contexts.
source and filesystem-context resolution. Establish which checks remain in 4. **Derive overlay context and separate lookup from containment.** Remove the
preflight and which require resolved main information. unconditional explicit-context requirement for the new layered default.
4. **Integrate underlays and overlays.** Resolve relative underlay files into Preserve explicit and ordinary lookup while enabling a main-directory lookup
ordinary acquisitions with their own import bases; derive the selected base inside a potentially wider root. Reuse selected-overlay loading and its
overlay context and reuse its loader. Preserve independent input contexts, failure and resource-ownership behavior.
namespace handling, cleanup on failure, and source/error evidence. 5. **Verify the complete workflow and document it.** Add maintained consumer
5. **Verify observable behavior and update documentation.** Add focused public examples, public integration coverage, and focused engine tests. Update the
coverage and maintained consumer examples, then update the discovery, discovery, layered-loading, import-context, and selected-overlay contracts,
layered-loading, and selected-overlay contracts, declaration comments, and declaration comments, and internal ownership documentation when implemented.
relevant internal ownership documentation. Explain the difference between a
file's directory and the configured root when they differ.
This is dependency order for a later implementation plan, not a required commit 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 layout or a requirement to expose intermediate stages to consumers.
existing lifecycle; a new discovery pass or a second configuration load is not
needed.
## Validation and completion ## 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 - Explicit and discovered main files, early and later search candidates, and an
the actual selection, including when it is outside the working directory. unrelated invocation directory. Companions follow the same selected main.
- Relative and independent underlays coexist; multiple groups retain precedence, - Mapping and bytes underlays containing optional named-file and recursive
and peers in one group retain strict-composition conflicts. directory imports with `*.yml`/`*.yaml` filtering and mounted destinations.
- Underlay imports use their own file's directory. Placement and source-version - File only, directory only, both, neither, empty directories, and invalid or
policies remain effective after binding. unreadable selected fragments. Both forms compose as peers when present.
- Active and inactive overlays, explicit contexts, optional search exhaustion, - Operator prompt overrides above embedded catalogs using registered identity;
and required-search failures follow the settled policies. same-tier duplicate IDs remain conflicts. Main and overlay precedence survive.
- Symlinked main files, explicit root overrides, parent-relative paths, and - Mixed embedded and companion inputs, multiple underlay tiers, transitive
namespace boundaries follow OD-3 and OD-4 without broadening existing access imports, placement, source-version checks, and load-wide import defaults.
guarantees. - Automatic derived overlays and explicit overrides, active and inactive names,
- Selected-file failures and dependent acquisition failures are terminal; no broader containment roots, and missing selected overlays.
repeated full load or duplicate defaults/resolution/validation callbacks are - Optional discovery exhaustion, required discovery, fallback and skip policies,
introduced. mixed payload/required-import cases from OD-2, and terminal selected-main errors.
- Source records, underlay indexes, origins, passive contexts, and failed-load - Symlinks, eligible namespaces, parent-relative paths within the selected scope,
evidence identify the actual acquired inputs. Existing handle cleanup and context validity, and namespace identity under OD-3 and OD-4.
budget accounting still cover dependent acquisitions. - Normal source evidence, diagnostics, passive resource contexts, cleanup, and
- Existing ordinary discovery and overlay loading, independent layered inputs, budget accounting; no duplicate lifecycle callbacks or preliminary full load.
and reuse of descriptions across loads retain their behavior. - Existing ordinary and explicit layered workflows and description reuse.
Run focused checks during implementation and the repository's applicable normal Run focused checks during implementation and applicable normal repository checks
checks before completion. No benchmark campaign or additional release gate is before completion. No benchmark campaign is required. Completion means the
required for this feature. Completion means applications can demonstrate the application can discover its main, bind companion imports and the selected
discovery-plus-relative-input workflow in one load, with documented public overlay, and receive normal resolved configuration and inspection in one load,
declarations and verified failure behavior. without an application directory walker, parser, or extra discovery pass.
## Open Decisions ## 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 **Settled:** companion `Mapping` and `Bytes` inputs must work; native imports own
underlay file and a main-derived overlay context. A dedicated underlay source fragment selection. Layered overlays derive automatically when no explicit
constructor and a small overlay context-selection option are plausible shapes; context is supplied. Concrete contexts override derivation as a whole.
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.
**Alternative:** add a general deferred filesystem-context descriptor shared by **Recommendation:** represent main-derived context as a small declarative choice
inputs and overlays. This could give context selection one uniform representation on an underlay `Input`, with a helper or constructor for the common case. Preserve
and accommodate later relationships, but risks expanding a small feature into its existing source, placement, import enablement, and tier. If both binding intent
a general context API. It is attractive if concrete API sketches show less and `Input.Filesystem` are supplied, use the concrete context without merging
duplication than separate declarations. Rejecting simultaneous explicit and fields. This is appropriate for mapping/bytes inputs because their context owns
derived overlay choices is also viable: it catches ambiguous setup, but requires import resolution; it does not reinterpret a file source's own path. Include the
callers to clear the derived choice when supplying an override. 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 ### OD-2: Scope and representation of absent-main handling
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.
**Alternative:** treat main-relative inputs as conditional on main presence and **Settled:** optional companions should support defaults-only startup; a declared
skip them after optional exhaustion. This supports defaults-only startup and is fallback is useful, and guessed candidate directories or implicit working-directory
consistent with a permissive search, but could silently omit an explicitly fallback are inappropriate. Selected-main failures remain terminal.
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.
### 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 **Alternative:** scope skip to the entire explicitly designated companion input.
file's directory, consistent with existing file/import behavior. Derive overlay This is simpler for the import-only mappings Audita describes and avoids partial
context from the main's resolved context, so overlay lookup remains relative to input processing, but also omits any payload or required imports in that input.
its configuration root. When an explicit main root is wider than the main It needs clear semantics for that deliberate condition. A single load-wide
directory, underlay filenames still use the directory as their base and overlays absence policy is another viable convenience, but cannot express different
use that root. Inherit the main's root for dependent underlay acquisition and requirements for separate companion inputs as directly.
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 `..`.
This distinguishes lookup from containment, reuses existing machinery, and ### OD-3: Containment inheritance and symlink convention
supports sibling directories under an explicitly wider root. It also means a
symlinked main selects resources beside its target, which must be documented.
**Alternative:** always create a fresh root at the main file's directory for **Settled:** derived companion imports and derived layered overlays use the main
both kinds of input. This makes every main-relative lookup visually local, file's directory for lookup, even with a wider configured containment root.
including with a wider main root, but discards intentional root configuration Explicit overlay contexts retain their current lookup semantics.
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.
### 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 **Alternative:** create a fresh containment root at the selected main directory.
`Filesystem.File` mains, using each namespace's existing path rules and resource This keeps companions locally scoped but discards intentional wider roots and
ownership. Discovery currently selects host files; a native file should not prevents some sibling-directory layouts. Anchoring to the lexical symlink directory
require discovery merely to provide the same directory relationship. Bind paths is also viable for deployment bundles; it differs from current file/import
within the selected namespace and reuse its identity. For this initial feature, behavior and would need distinct lookup and containment handling.
byte, reader, mapping, and absent mains do not supply a main-file directory;
independently specified contexts remain available for those workflows.
**Alternative:** derive from any resolved main filesystem context, including an ### OD-4: Main-source eligibility beyond discovered host files
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, **Settled:** both explicitly selected and discovered host mains support the
but changes the concept from relative-to-main-file to relative-to-main-context. workflow. Non-file companion inputs, especially mappings and bytes, are in scope;
It needs explicit rules for absent mains and root-only contexts, where root and this decision concerns the main input that supplies their base.
base are not interchangeable. Limiting the first implementation to host files
is also viable and smaller, but would leave native-filesystem consumers with **Recommendation:** also support native `Filesystem.File` mains using their
the same coordination gap. 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.