Define discovery filename groups and search presets
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
# Composable Configuration Discovery Roadmap
|
# Composable Configuration Discovery Roadmap
|
||||||
|
|
||||||
Status: proposal with the agreed direction captured below. Preset contents and
|
Status: proposal with the agreed direction, filename groups, and Unix system
|
||||||
the remaining behavioral choices are under [Open Decisions](#open-decisions).
|
preset captured below. Remaining preset and behavioral choices are under
|
||||||
|
[Open Decisions](#open-decisions).
|
||||||
This document describes future work, not an implemented contract. A staged
|
This document describes future work, not an implemented contract. A staged
|
||||||
implementation plan will follow once the decisions are settled.
|
implementation plan will follow once the decisions are settled.
|
||||||
|
|
||||||
@@ -43,13 +44,76 @@ library-provided search conventions. Consumer ownership remains unchanged.
|
|||||||
|
|
||||||
## Agreed Direction
|
## Agreed Direction
|
||||||
|
|
||||||
### Ordered Candidate Groups
|
### Filename Groups, Directory Searches, And Search Presets
|
||||||
|
|
||||||
Provide reusable descriptions of built-in search lists and custom ordered paths.
|
Organize discovery around three composable descriptions. These are ordered lists:
|
||||||
Consumers select one or more groups in the desired order. Conceptually, concatenate
|
their order determines precedence.
|
||||||
the groups into one ordered candidate sequence, preserving order within each
|
|
||||||
group. This is ordered concatenation followed by first-match selection, not a
|
**Filename groups** provide reusable, ordered filename templates. The built-in
|
||||||
set union or a precedence merge.
|
groups are:
|
||||||
|
|
||||||
|
| Group | Filenames, in order |
|
||||||
|
| --- | --- |
|
||||||
|
| Named | `<appname>.yml`, `<appname>.yaml` |
|
||||||
|
| Generic | `config.yml`, `config.yaml`, `main.yml`, `main.yaml` |
|
||||||
|
|
||||||
|
`<appname>` is the application slug supplied by the consumer.
|
||||||
|
|
||||||
|
**Directory searches** pair a directory with an ordered list of filename groups.
|
||||||
|
The default selection is `[Named, Generic]`, producing the six filenames above
|
||||||
|
in that order. A directory search may select different groups or reverse their
|
||||||
|
precedence, such as `[Generic, Named]`, while retaining each group's internal
|
||||||
|
order. Consumers can also supply custom filenames.
|
||||||
|
|
||||||
|
**Search presets** bundle ordered directory searches. Consumers can select a
|
||||||
|
complete preset for the simple case or compose presets, custom directory searches,
|
||||||
|
and explicit file candidates in their desired order. Explicit file candidates
|
||||||
|
are literal paths and receive no filename expansion.
|
||||||
|
|
||||||
|
### Ordered Expansion And Concatenation
|
||||||
|
|
||||||
|
The selection model is **ordered expansion and concatenation**, followed by
|
||||||
|
first-match selection:
|
||||||
|
|
||||||
|
1. Expand the selected presets into directory searches in their supplied order.
|
||||||
|
2. For each directory search, concatenate its selected filename groups in order,
|
||||||
|
substitute the application slug where needed, and join each filename to that
|
||||||
|
directory.
|
||||||
|
3. Concatenate the resulting candidate lists, preserving the positions of custom
|
||||||
|
directory searches and explicit file candidates.
|
||||||
|
4. Try candidates in order, stopping at the first selected file or an error as
|
||||||
|
described below.
|
||||||
|
|
||||||
|
Directory priority comes before filename priority: exhaust one directory's
|
||||||
|
filenames before trying the next directory. When several directories share a
|
||||||
|
filename list, their expansion is a Cartesian product traversed directory first.
|
||||||
|
Different directories may select different lists, so ordered expansion and
|
||||||
|
concatenation describes the complete model. Set union does not express its
|
||||||
|
precedence semantics.
|
||||||
|
|
||||||
|
The eventual documentation should explain this model using the applicable
|
||||||
|
mathematical nomenclature: ordered lists, ordered concatenation, and Cartesian
|
||||||
|
product where a shared filename list applies. Retain these names in relevant
|
||||||
|
implementation comments where they help readers understand the operations. The
|
||||||
|
model describes ordering without requiring eager construction of every candidate.
|
||||||
|
|
||||||
|
### Unix System Preset
|
||||||
|
|
||||||
|
The agreed Unix system preset is:
|
||||||
|
|
||||||
|
| Directory, in search order | Filename groups, in order |
|
||||||
|
| --- | --- |
|
||||||
|
| `/usr/local/etc/<appname>` | `[Named, Generic]` |
|
||||||
|
| `/etc/<appname>` | `[Named, Generic]` |
|
||||||
|
| `/etc` | `[Named]` |
|
||||||
|
|
||||||
|
This produces 14 candidates: six in each application-specific directory, then
|
||||||
|
`/etc/<appname>.yml` and `/etc/<appname>.yaml`. For example,
|
||||||
|
`/usr/local/etc/<appname>/main.yaml` precedes
|
||||||
|
`/etc/<appname>/<appname>.yml`. Selecting only `Named` for `/etc` is an ordinary
|
||||||
|
directory-search description; the selection algorithm needs no special exception.
|
||||||
|
|
||||||
|
### Illustrative Consumer API
|
||||||
|
|
||||||
Names below are illustrative and are not implemented Go API:
|
Names below are illustrative and are not implemented Go API:
|
||||||
|
|
||||||
@@ -78,8 +142,9 @@ source := configkit.SearchConfig(
|
|||||||
```
|
```
|
||||||
|
|
||||||
Use the resulting source with ordinary loading or as a layered main input. Custom
|
Use the resulting source with ordinary loading or as a layered main input. Custom
|
||||||
lists participate at their specified position; they do not silently append
|
searches and file lists participate at their specified position; they do not
|
||||||
unselected built-in defaults. Reordering groups changes search priority.
|
silently append unselected presets. Reordering presets or their directory
|
||||||
|
searches changes search priority.
|
||||||
|
|
||||||
### Selection And Failure Behavior
|
### Selection And Failure Behavior
|
||||||
|
|
||||||
@@ -93,9 +158,9 @@ unselected built-in defaults. Reordering groups changes search priority.
|
|||||||
| Entire search has no match and is required | Fail with a diagnostic explaining the unsuccessful search. |
|
| Entire search has no match and is required | Fail with a diagnostic explaining the unsuccessful search. |
|
||||||
| Caller explicitly uses `File(path)` | Retain existing exclusive-file behavior, including errors for a missing file. |
|
| Caller explicitly uses `File(path)` | Retain existing exclusive-file behavior, including errors for a missing file. |
|
||||||
|
|
||||||
Requiredness applies to the complete search, not to each group. Permitting an
|
Requiredness applies to the complete search, not to each preset or directory.
|
||||||
absent file does not waive application version, schema, or domain requirements;
|
Permitting an absent file does not waive application version, schema, or domain
|
||||||
the remaining lifecycle may still reject an incomplete configuration.
|
requirements; the remaining lifecycle may still reject an incomplete configuration.
|
||||||
|
|
||||||
Perform discovery before parsing the chosen main file. Do not implement fallback
|
Perform discovery before parsing the chosen main file. Do not implement fallback
|
||||||
by repeatedly running complete loads. Defaults, application resolution, secret
|
by repeatedly running complete loads. Defaults, application resolution, secret
|
||||||
@@ -142,25 +207,31 @@ An explicitly selected overlay is not another main-file fallback candidate.
|
|||||||
|
|
||||||
The subsequent implementation plan should cover:
|
The subsequent implementation plan should cover:
|
||||||
|
|
||||||
- Define candidate-group and search-source representations, slug validation, and
|
- Define filename-group, directory-search, preset, and search-source representations,
|
||||||
a search-wide requiredness option. Keep construction separate from acquisition.
|
slug validation, and a search-wide requiredness option. Keep construction
|
||||||
- Implement the selected preset expansions, ordered custom paths, and first-match
|
separate from acquisition and the simple preset selection concise.
|
||||||
selection through existing file access. Resolve each source once per consumption
|
- Implement ordered expansion and concatenation for presets, filename groups,
|
||||||
before entering its parse and composition lifecycle.
|
custom searches, and explicit file candidates, followed by first-match selection
|
||||||
|
through existing file access. Resolve each source once per consumption before
|
||||||
|
entering its parse and composition lifecycle.
|
||||||
- Integrate selected and absent outcomes with ordinary and layered main inputs,
|
- Integrate selected and absent outcomes with ordinary and layered main inputs,
|
||||||
placement, imports, application version checking, and overlay contexts according
|
placement, imports, application version checking, and overlay contexts according
|
||||||
to OD-3. Preserve ownership and close acquired handles on success and failure.
|
to OD-3. Preserve ownership and close acquired handles on success and failure.
|
||||||
- Preserve real selected-source metadata and safe diagnostics without treating
|
- Preserve real selected-source metadata and safe diagnostics without treating
|
||||||
absent candidates as configuration contributions.
|
absent candidates as configuration contributions.
|
||||||
- Exercise candidate and group ordering, custom-list composition, both filename
|
- Exercise preset, directory, filename-group, and filename ordering, reversed
|
||||||
extensions, no-match behavior, required searches, unavailable preset bases,
|
group precedence, the Unix system preset's 14 candidates and named-only `/etc`
|
||||||
errors that must stop fallback, repeated loads, and untouched explicit `File`
|
search, custom-list composition, both filename extensions, no-match behavior,
|
||||||
|
required searches, unavailable preset bases, errors that must stop fallback,
|
||||||
|
repeated loads, and untouched explicit `File`
|
||||||
behavior. Cover imports, overlays, underlays, defaults, CLI, source versions,
|
behavior. Cover imports, overlays, underlays, defaults, CLI, source versions,
|
||||||
source contexts, and source-list/inspection evidence at their boundaries.
|
source contexts, and source-list/inspection evidence at their boundaries.
|
||||||
- Clarify the architecture policy's consumer-selected discovery boundary. Record
|
- Clarify the architecture policy's consumer-selected discovery boundary. Record
|
||||||
any warranted durable ownership decision in an ADR; keep preset filenames and
|
any warranted durable ownership decision in an ADR; keep preset filenames and
|
||||||
API mechanics in their canonical contract when implemented. Update consumer
|
API mechanics in their canonical contract when implemented. Update consumer
|
||||||
examples and the configuration contract when the feature lands.
|
examples and the configuration contract when the feature lands. Explain the
|
||||||
|
three-part discovery model and its mathematical terminology in the eventual
|
||||||
|
documentation, with simple preset selection and custom composition examples.
|
||||||
|
|
||||||
This roadmap does not change implementation, policy, or ADRs by itself. Coordinate
|
This roadmap does not change implementation, policy, or ADRs by itself. Coordinate
|
||||||
implementation with the ongoing sequence integration audit rather than assuming
|
implementation with the ongoing sequence integration audit rather than assuming
|
||||||
@@ -168,54 +239,48 @@ its in-progress changes are part of a fixed implementation baseline.
|
|||||||
|
|
||||||
## Open Decisions
|
## Open Decisions
|
||||||
|
|
||||||
### OD-1 — Preset Contents And Filename Order
|
### OD-1 — Additional Preset Locations
|
||||||
|
|
||||||
**Recommendation:** begin with three explicitly selected presets. Try `.yml`
|
The filename groups, default `[Named, Generic]` order, and Unix system preset
|
||||||
before `.yaml` at each location, completing both alternatives there before moving
|
are settled above. The remaining choice is which additional directory conventions
|
||||||
to the next location:
|
to provide as presets.
|
||||||
|
|
||||||
| Preset | Candidate locations, in order |
|
**Recommendation:** also provide user-configuration and working-directory presets:
|
||||||
| --- | --- |
|
|
||||||
| Unix system | `/usr/local/etc/<slug>/config.yml`, `/usr/local/etc/<slug>/config.yaml`, `/etc/<slug>/config.yml`, `/etc/<slug>/config.yaml`, `/etc/<slug>.yml`, `/etc/<slug>.yaml` |
|
| Preset | Directory | Filename groups, in order |
|
||||||
| User configuration | `<user-config-dir>/<slug>/config.yml`, then `config.yaml` in the same directory |
|
| --- | --- | --- |
|
||||||
| Working directory | `./<slug>.yml`, then `./<slug>.yaml` |
|
| User configuration | `<user-config-dir>/<appname>` | `[Named, Generic]` |
|
||||||
|
| Working directory | Current working directory | `[Named, Generic]` |
|
||||||
|
|
||||||
For the user preset, use Go's platform-specific
|
For the user preset, use Go's platform-specific
|
||||||
[`os.UserConfigDir`](https://pkg.go.dev/os#UserConfigDir) as the base. This supplies
|
[`os.UserConfigDir`](https://pkg.go.dev/os#UserConfigDir) as the base. This supplies
|
||||||
a conventional user location without inventing separate home-directory rules.
|
a conventional user location without inventing separate home-directory rules.
|
||||||
The system list retains the originally proposed location order. Application-named
|
The working-directory preset searches that directory without walking ancestors.
|
||||||
working-directory files make the selected application's convention explicit.
|
Both reuse the agreed default filename groups.
|
||||||
No preset walks ancestor directories.
|
|
||||||
|
|
||||||
**Alternative:** use `./config.yml` and `./config.yaml` for the working-directory
|
**Alternative:** provide a home-directory convention, such as
|
||||||
preset, or add them after the application-named files. Generic names are concise
|
`~/.<appname>/` with `[Named, Generic]`, instead of or alongside the
|
||||||
for project-local applications, while application-named files distinguish
|
user-config-directory preset. It is familiar for some tools, but providing both
|
||||||
applications sharing a working directory. Adding both is convenient but expands
|
adds another convention for consumers to select and order. Prefer the
|
||||||
the candidate list and makes a generic file a fallback even when the consumer
|
user-config-directory preset initially; custom searches can express other layouts.
|
||||||
intended an application-specific convention.
|
|
||||||
|
|
||||||
An additional viable user convention is a home-directory dotfile or directory,
|
|
||||||
such as `~/.<slug>.yml` or `~/.<slug>/config.yml`. It is familiar for some tools,
|
|
||||||
but would add a second user convention and ordering to explain. Prefer the
|
|
||||||
user-config-directory preset initially; custom paths can express other layouts.
|
|
||||||
|
|
||||||
### OD-2 — Unavailable Bases And Platform Applicability
|
### OD-2 — Unavailable Bases And Platform Applicability
|
||||||
|
|
||||||
**Recommendation:** resolve group bases as the ordered search reaches them.
|
**Recommendation:** resolve directory bases as the ordered search reaches them.
|
||||||
If a selected group's base cannot be resolved, report an error. Treat using the
|
If a selected directory's base cannot be resolved, report an error. Treat using the
|
||||||
Unix system preset on a platform where it is unsupported as an explicit
|
Unix system preset on a platform where it is unsupported as an explicit
|
||||||
configuration error when that group is reached. Specify the supported platforms
|
configuration error when that preset is reached. Specify the supported platforms
|
||||||
in the implementation plan. Do not silently translate the Unix preset into a
|
in the implementation plan. Do not silently translate the Unix preset into a
|
||||||
different platform's convention. User and working-directory presets use their
|
different platform's convention. User and working-directory presets use their
|
||||||
platform-native bases.
|
platform-native bases.
|
||||||
|
|
||||||
An unavailable base is different from a candidate file being absent. Failure to
|
An unavailable base is different from a candidate file being absent. Failure to
|
||||||
determine the user's configuration directory should not silently redirect loading
|
determine the user's configuration directory should not silently redirect loading
|
||||||
to a different group. Once an earlier candidate is selected, later groups need
|
to a different directory. Once an earlier candidate is selected, later searches need
|
||||||
not resolve their bases. Static invalid search arguments still fail ordinary
|
not resolve their bases. Static invalid search arguments still fail ordinary
|
||||||
option validation before source acquisition.
|
option validation before source acquisition.
|
||||||
|
|
||||||
**Alternative:** treat unsupported presets or unavailable bases as empty groups
|
**Alternative:** treat unsupported presets or unavailable bases as empty searches
|
||||||
and continue. This makes one preset composition usable across more environments,
|
and continue. This makes one preset composition usable across more environments,
|
||||||
but can unexpectedly select a lower-priority configuration. A selectable
|
but can unexpectedly select a lower-priority configuration. A selectable
|
||||||
skip-unavailable behavior could serve that need later; it adds a distinct policy
|
skip-unavailable behavior could serve that need later; it adds a distinct policy
|
||||||
@@ -248,14 +313,15 @@ case could avoid changing `NoSource()`, at the cost of two different absence rul
|
|||||||
|
|
||||||
### OD-4 — Empty Composition And Implicit Preset Selection
|
### OD-4 — Empty Composition And Implicit Preset Selection
|
||||||
|
|
||||||
**Recommendation:** require explicit group selection to activate a convention.
|
**Recommendation:** require explicit preset or search selection to activate a
|
||||||
An empty group composition has no candidates: optional search contributes no
|
convention. An empty search composition has no candidates: optional search contributes no
|
||||||
source, and required search fails as exhausted. Empty custom lists follow the
|
source, and required search fails as exhausted. Empty custom lists, including
|
||||||
same rule. This supports programmatic list construction and introduces no hidden
|
empty filename-group selections, follow the same rule. This supports programmatic
|
||||||
|
list construction and introduces no hidden
|
||||||
system, user, or working-directory fallback. One explicitly selected preset
|
system, user, or working-directory fallback. One explicitly selected preset
|
||||||
still gives the simple application a short call.
|
still gives the simple application a short call.
|
||||||
|
|
||||||
**Alternative:** let omission of groups select a documented default preset.
|
**Alternative:** let omission of searches select a documented default preset.
|
||||||
This shortens the simplest call, but omission and an intentionally empty computed
|
This shortens the simplest call, but omission and an intentionally empty computed
|
||||||
list would need distinguishable representations. It also requires choosing a
|
list would need distinguishable representations. It also requires choosing a
|
||||||
default convention across platforms and application styles. Another alternative
|
default convention across platforms and application styles. Another alternative
|
||||||
|
|||||||
Reference in New Issue
Block a user