Plan import discovery and shared dependency ordering
This commit is contained in:
566
docs/roadmap/implementation.md
Normal file
566
docs/roadmap/implementation.md
Normal file
@@ -0,0 +1,566 @@
|
||||
# Implementation Plan: Import Discovery and Dependency-Ready Ordering
|
||||
|
||||
Status: planned; no implementation stages completed.
|
||||
|
||||
## Authority, baseline, and execution
|
||||
|
||||
Implement the accepted [import roadmap](imports.md),
|
||||
[ADR 0015](../adr/0015-shared-dependency-ready-ordering.md), and
|
||||
[ADR 0016](../adr/0016-independent-import-controls.md), starting at
|
||||
`94381a67fd39635f448a5225e38adb2a7f43cc9f`. The roadmap owns target behavior and
|
||||
scope; this plan settles delivery order and the remaining implementation choices.
|
||||
The accepted ADRs already exist; do not draft replacements or rewrite their
|
||||
decision text.
|
||||
|
||||
The implementer is a Luna coding agent. Execute one numbered stage per focused
|
||||
prompt, in order. Each stage should end with a validated, nonempty commit and a
|
||||
completion entry here identifying the commit, checks, and any remaining work.
|
||||
Do not mark a stage complete while its acceptance conditions remain unmet.
|
||||
Preserve unrelated work. This planning pass changes documentation only.
|
||||
|
||||
Start with [development](../development.md) and read the applicable
|
||||
[agent](../policy/agents.md), [architecture](../policy/architecture.md),
|
||||
[testing](../policy/testing.md), and [documentation](../policy/documentation.md)
|
||||
policies. Prefer the code graph for discovery, then inspect current source and
|
||||
tests; indexed snippets can have stale line ranges. Use the actual working tree
|
||||
when an indexed snippet is incomplete or mismatched.
|
||||
|
||||
Keep each stage's public documentation accurate to its implemented boundary.
|
||||
Private groundwork may precede wiring, but do not expose options that silently
|
||||
do nothing. The final syntax cutover is Stage 14; there is no consumer-facing
|
||||
compatibility mode, alias, or alternate scheduler. Intermediate private helpers
|
||||
are scaffolding, not a second supported interface. Release publication and
|
||||
consumer dependency updates are outside this plan.
|
||||
|
||||
## Settled implementation choices
|
||||
|
||||
### Public defaults
|
||||
|
||||
Add a root-owned `ImportDefaults` struct and an `ImportDefaults ImportDefaults`
|
||||
field to both `Options[T]` and `LayeredOptions[T]`:
|
||||
|
||||
```go
|
||||
type ImportDefaults struct {
|
||||
Required *bool
|
||||
Follow *bool
|
||||
Hidden *bool
|
||||
Recursive *bool
|
||||
Pattern []string
|
||||
}
|
||||
```
|
||||
|
||||
Nil boolean pointers mean unspecified. Copy pointed-to values when loading
|
||||
begins. Nil `Pattern` means unspecified; non-nil empty means select nothing for
|
||||
directory searches. Snapshot the slice without collapsing this distinction.
|
||||
No new defaults field belongs on `Input`, `Underlay`, or `Definition`: one
|
||||
load-level selection applies to main and all underlay/transitive import
|
||||
declarations. Existing per-input `Imports` booleans still enable imports.
|
||||
|
||||
Resolve each applicable declaration field independently: explicit declaration,
|
||||
then application default, then library default. Library defaults are required
|
||||
false, recursive false, follow true, hidden true, and unrestricted filenames.
|
||||
No parent-declaration inheritance, enforced application override, default
|
||||
exclusion list, or application depth setting is added. `pattern` replaces rather
|
||||
than augments the default. Validate supplied default patterns once at option
|
||||
selection, reporting `options.invalid` before source reads or callbacks.
|
||||
Defaults do not make unsupported fields applicable to a selector.
|
||||
|
||||
Use a private presence-aware declaration representation, distinct from its
|
||||
resolved discovery policy. Normalize scalar/list selectors and filters once.
|
||||
Keep existing import path validity rules, with `.` accepted for literal directory
|
||||
roots. Match basenames with case-sensitive `path.Match`; path globs retain their
|
||||
existing grammar, including rejection of recursive `**`. A filename filter has
|
||||
no directory-recursion interpretation. Validate all expressions even in empty
|
||||
or otherwise inactive selections. Follow the roadmap's option applicability,
|
||||
empty-list, null, and depth rules exactly.
|
||||
|
||||
`depth` has no arbitrary machine-integer maximum. Accept nonnegative YAML
|
||||
integers under the existing scalar rules, including bounds larger than can be
|
||||
reached under the visit budget; an implementation may saturate its internal
|
||||
bound at the largest representable traversal depth without rejecting that input.
|
||||
Numeric `-0` denotes zero. Do not accept fractional/exponent numbers as integer
|
||||
depth or coerce strings.
|
||||
|
||||
### No-selection inspection
|
||||
|
||||
Extend root-owned `SourceInfo` with `ImportSelections []ImportSelection`. Add
|
||||
root-owned string types and constants:
|
||||
|
||||
- `ImportSelector`: `ImportSelectorPath = "path"`, `ImportSelectorDirectory =
|
||||
"dir"`, and `ImportSelectorGlob = "glob"`.
|
||||
- `ImportSelectionOutcome`: `ImportSelectionNone = "none"`.
|
||||
- `ImportSelection` fields: `Path Path`, `Location Location`,
|
||||
`Selector ImportSelector`, and `Outcome ImportSelectionOutcome`.
|
||||
|
||||
`Path` is the source-local declaration path, such as
|
||||
`/configkit/imports/0`; `Location` identifies the declaring mapping and carries
|
||||
its actual SourceID. Attach one record to that declaring source for each
|
||||
effectively optional declaration whose entire selected set is empty. Keep
|
||||
records in declaration order. Do not record partial omissions, candidate lists,
|
||||
raw selector values, inferred missing-file reasons, warnings, or fake sources.
|
||||
Required empty `path: []` succeeds but gets no optional-declaration record.
|
||||
|
||||
Reuse `Result.Sources`, `LoadError.Sources`, and callback source snapshots rather
|
||||
than adding another query surface. Snapshots contain only outcomes established
|
||||
by that point; no complete discovery record is promised after an earlier error.
|
||||
Records remain source-local through mounting and item placement. Deep-copy paths
|
||||
and slices through engine cloning and facade conversion. Existing version-text
|
||||
redaction remains independent and unchanged.
|
||||
|
||||
### Scheduling and identities
|
||||
|
||||
Keep the shared scheduler private to `internal/engine`, in a focused
|
||||
`dependency_order.go` owner; no new public scheduling API or dependency is needed.
|
||||
It accepts immutable node keys and dependency edges and returns a complete order
|
||||
or an actual closed cycle. Use Kahn's algorithm and `container/heap`; deduplicate
|
||||
edges before counting dependencies. Compute keys once. Compare key tuples by Go
|
||||
bytewise string order component by component, shorter tuple first on a prefix.
|
||||
|
||||
Use these key constructions in both integrations:
|
||||
|
||||
- Import nodes: `(namespace-kind, namespace-anchor, resource-kind, resource-path)`.
|
||||
Kind is `host` or `native`; resource kind is `file` or `synthetic`. Host paths
|
||||
are canonical absolute paths rendered with slash separators; native paths use
|
||||
their existing namespace-relative identity. Synthetic roots use their explicit
|
||||
input anchor, not a label or allocated token address.
|
||||
- Derive namespace anchors from explicit request positions, never discovery.
|
||||
Positions are main `(0,0)` and underlay/input `(group+1,input+1)`. Encode each
|
||||
numeric component in fixed-width decimal sufficient for a Go index. All host
|
||||
accesses within one scheduled tier share its host anchor; each native token
|
||||
uses the smallest explicit input position selecting that namespace in that
|
||||
tier. Same-label, separately constructed filesystems remain distinct. Use
|
||||
tokens to identify equality, not to order nodes.
|
||||
- Inheritance nodes: `("definition", scope-pointer, definition-pointer)` using
|
||||
canonical escaped semantic pointers. Within a sibling scope these distinguish
|
||||
exact names, including empty or escaped keys. No source ID participates.
|
||||
|
||||
The tuple comparator is shared; resolver-specific key construction is not a
|
||||
second ordering algorithm. Unique keys are an internal construction requirement,
|
||||
not a new user configuration restriction. Imports already reject repeated
|
||||
canonical inclusion; separate synthetic roots have distinct explicit anchors.
|
||||
|
||||
For a stalled graph, deterministically traverse residual dependencies using
|
||||
explicit DFS state, visiting nodes and neighbors in key order. Return an actual
|
||||
stack cycle, rotated to begin at its smallest key, with the start repeated at
|
||||
the end. Exclude blocked non-cycle dependents. Both resolvers translate these
|
||||
node/edge identities to existing domain diagnostic codes and authored sites;
|
||||
do not expose inheritance names or payload values in messages. Preserve import
|
||||
cycle-site evidence. Build deterministic adjacency from precomputed node ranks
|
||||
in linear edge work, rather than repeatedly sorting the ready set or scanning
|
||||
all nodes for each completion. Scheduling costs O(E + V log V), O(V + E) memory,
|
||||
apart from key construction/comparison and domain operations.
|
||||
|
||||
### Discovery, scopes, and assembly
|
||||
|
||||
Keep acquisition deterministic and separate from application. Enumerate
|
||||
declarations in authored order; normalize/deduplicate a declaration's selected
|
||||
candidate paths and visit them in namespace-path lexical order. Keep main-first
|
||||
acquisition records, IDs, source-local version checking, and physical import
|
||||
resolution. This discovery order does not determine sequence assembly order.
|
||||
There is no new first-error or no-read-before-error guarantee.
|
||||
|
||||
Represent dependencies while acquiring files. Ordinary source-body nodes depend
|
||||
on their imported contributions; importing bodies therefore assemble after
|
||||
their dependencies. Record source roles explicitly: the main body must not be
|
||||
identified as contribution index zero after scheduling. Keep all source IDs and
|
||||
authored locations attached to contributions when reordering them.
|
||||
|
||||
Each main tier or underlay group has one outer strict-scope graph, including all
|
||||
its independent input roots and ordinary imports. An item contribution is one
|
||||
outer node keyed by its owning source. It owns a nested strict mapping-scope
|
||||
graph containing that source body, ordinary helper contributions, and further
|
||||
item nodes. Prevalidate the available scope schedules before applying their
|
||||
operations. When the outer schedule selects an item node, execute its validated
|
||||
local schedule, compose the item mapping, then place the completed item into
|
||||
the outer scope. Do not globally flatten helper bodies into the collection.
|
||||
Resolve local paths and project final indexes using that actual scheduled
|
||||
contribution order. Main-item and underlay-item roots use the same model.
|
||||
|
||||
Retain the acquisition/inclusion graph independently of these composition scope
|
||||
boundaries so cycles crossing item boundaries remain detectable. On an active
|
||||
canonical repeat, retain the closing edge without rereading the source and use
|
||||
the shared cycle logic on the available inclusion graph. Non-active repeated
|
||||
inclusion still fails as `import.repeated`; no successful diamond import or
|
||||
global source deduplication is introduced.
|
||||
|
||||
Within inheritance, construct the graph of direct mapping siblings and their
|
||||
string parent edges, validate it, then produce templates in scheduled order.
|
||||
Null cancels a relationship without an edge. Keep enclosing-before-nested
|
||||
destination-local traversal and unresolved nested templates, as in ADR 0009.
|
||||
Do not reorder output mappings merely to mirror scheduling.
|
||||
|
||||
Directory discovery keeps candidate spellings separate from canonical access.
|
||||
One normalized candidate path per namespace is selected once per declaration;
|
||||
aliases retain separate candidates and existing admission rules. Directory
|
||||
filters run on discovered names. Exclusions never read content, but do not hide
|
||||
discovery, containment, or resource failures. For required named paths, verify
|
||||
every listed target exists even if excluded, without parsing excluded content.
|
||||
|
||||
Use existing bounded directory reads. For distinct roots, traverse each search
|
||||
with its applicable depth once and test the union of filename patterns per
|
||||
file; do not walk once per root/pattern pair. Overlapping roots may revisit
|
||||
entries under the existing visit accounting, but selected candidates deduplicate.
|
||||
Do not use global canonical-directory visitation to silently suppress aliases.
|
||||
Charge selected-source allowance after exclusions and local deduplication;
|
||||
discovery entries still count throughout, and excluded content costs no bytes.
|
||||
|
||||
Use host `Lstat`/root-relative operations for discovery controls and the standard
|
||||
native `fs.ReadLinkFS` capability where available. Follow the supplied filesystem's
|
||||
capabilities; do not require every `fs.FS` to implement link inspection or turn
|
||||
opaque native behavior into a universal sandbox guarantee. Host directory cycle
|
||||
keys are canonical paths; link-aware native traversal uses the corresponding
|
||||
resolved namespace directory identity. This traversal identity must not silently
|
||||
change the existing native source-admission identity. Track canonical directories
|
||||
on the active traversal path, not all previously visited directories. Distinguish
|
||||
directory traversal cycles from import dependency cycles; use `import.cycle`
|
||||
with the declaring site and a safe directory-cycle message for the former.
|
||||
|
||||
## Stage 1 — Build the shared scheduler
|
||||
|
||||
Create the private scheduler, tuple comparator, min-heap, and deterministic
|
||||
cycle finder specified above. Keep it independent of documents, filesystem
|
||||
handles, diagnostics, and callbacks. Document Kahn's algorithm, actual-cycle
|
||||
identification, and complexity beside its owner.
|
||||
|
||||
Tests own observable schedules: independent branches, unequal chains, multiple
|
||||
dependencies, shared dependencies at equal/unequal depths, a newly ready small
|
||||
key preceding an older large key, duplicate edges, self/multi-node cycles, and
|
||||
blocked non-cycle dependents. Permute insertion order while retaining keys and
|
||||
assert equal schedules/cycles. Do not assert heap internals.
|
||||
|
||||
Acceptance: focused scheduler tests pass; no loading behavior changes.
|
||||
|
||||
## Stage 2 — Separate inheritance graph analysis from application
|
||||
|
||||
In `inheritance.go`, extract direct-sibling relationship analysis from the
|
||||
existing stack-driven application loop. Build keyed mapping nodes and edges;
|
||||
retain null controls, missing/non-mapping parent diagnostics, exact directive
|
||||
sites, and non-mapping siblings. Add a scheduled template-application helper
|
||||
reusing current merge hooks, origins, retained-node accounting, and unresolved
|
||||
nested template behavior. Keep the currently wired resolver unchanged until
|
||||
Stage 3; do not expose an alternate public path.
|
||||
|
||||
Acceptance: private scope tests demonstrate the shared schedule, ordinary/null
|
||||
relationships, real cycle sites, and preserved template values/ownership.
|
||||
|
||||
## Stage 3 — Integrate scheduled inheritance
|
||||
|
||||
Replace the old sibling-frame resolution in the loading path with Stage 2's
|
||||
analysis and application. Remove superseded stack/state machinery. Retain
|
||||
`inheritance_walk.go`'s enclosing-before-nested scope discovery, sequence
|
||||
traversal, final projection budgets, and immutable retained evidence.
|
||||
|
||||
Review inheritance history/control/transfer ordering against the selected
|
||||
schedule, not the old DFS order. Add one unequal-branch integration case and
|
||||
reuse existing nested destination, cancellation, sensitivity, version ownership,
|
||||
and budget tests. Update the owning inheritance contract and internal overview
|
||||
to describe implemented scheduling, linking ADR 0015.
|
||||
|
||||
Acceptance: inheritance and facade inheritance suites pass; final values,
|
||||
presence, origins, and explanation agree; no alternate resolver remains.
|
||||
|
||||
## Stage 4 — Retain the import inclusion graph during acquisition
|
||||
|
||||
Refactor `imports.go` and `load_input.go` so acquired contributions carry stable
|
||||
source identity, role, inclusion edges, and explicit scope ownership, rather
|
||||
than treating their slice position as both acquisition and application order.
|
||||
Separate item discovery from immediate item composition. Preserve parsed
|
||||
payloads and source-version processing results without rereading sources.
|
||||
|
||||
Keep existing wired application order for this extraction stage. Introduce the
|
||||
stable import keys and include-cycle integration with the shared cycle finder;
|
||||
keep non-active repeats invalid, including aliases and different inclusion
|
||||
routes. Do not expand successful shared dependency support for imports.
|
||||
|
||||
Acceptance: current ordinary/item import behavior tests pass, including a cycle
|
||||
through a nested item scope, repeated imports, source IDs, and handle closure.
|
||||
|
||||
## Stage 5 — Schedule ordinary main-tier contributions
|
||||
|
||||
Use the shared scheduler for ordinary mapping contributions in the main tier.
|
||||
Plan before composing. The main body follows its import dependencies; independent
|
||||
ready branches follow stable keys. Reuse `composeDocumentsWithPolicy` and the
|
||||
existing merge primitives. Update the corresponding order tests deliberately.
|
||||
|
||||
Replace assumptions that main is document/contribution zero in
|
||||
`importedVersionClaim`, source-root ownership, contexts, and history. Carry an
|
||||
explicit main source ID/role and locate its scheduled contribution. Keep source
|
||||
enumeration and version callbacks in acquisition order. Default-mode effective
|
||||
version checking still happens after main-tier assembly.
|
||||
|
||||
Acceptance: ordinary import values, registered sequence order, conflict sites,
|
||||
main-version protection, source records, and authored resource contexts agree.
|
||||
Document this implemented ordering boundary in the import contract.
|
||||
|
||||
## Stage 6 — Assemble item-local scopes under the scheduler
|
||||
|
||||
Integrate item nodes and local schedules for imported and selected main items.
|
||||
Complete helpers before local item assembly and outer placement. Reuse existing
|
||||
`projectNestedEvidence`, destination projection, sequence ranges, and diagnostic
|
||||
projection, correcting any assumptions about contribution order or index zero.
|
||||
Do not register application collection policies inside helper mapping scopes.
|
||||
|
||||
Keep local version checking/consumption before assembly and project retained
|
||||
source evidence through the actual assigned indexes. Failed-load source paths
|
||||
retain the existing unresolved-container semantics until indexes are known;
|
||||
do not invent an exact index to simplify a failure.
|
||||
|
||||
Acceptance: nested items, helper-supplied IDs, main items, multiple unequal
|
||||
branches, physical coordinates, sensitivity, history chronology, and item
|
||||
conflict paths pass engine and public tests. Run the focused race suite.
|
||||
|
||||
## Stage 7 — Schedule underlay forests and preserve tier boundaries
|
||||
|
||||
In `load_request.go`, acquire all roots in a strict underlay group before
|
||||
scheduled group assembly. Combine their retained scope graphs rather than
|
||||
concatenating already composed per-input orders. Assign namespace anchors from
|
||||
explicit input positions. Include inputs without imports and item roots.
|
||||
|
||||
Keep per-tier repeated-source state, accounting, main acquisition timing, and
|
||||
underlay precedence unchanged. Independent groups never enter one scheduler;
|
||||
overlays/CLI remain later precedence operations. Maintain source layers,
|
||||
underlay indexes, global source IDs, and group-wide item path projections.
|
||||
|
||||
Acceptance: a group with interleaving dependency branches across input roots
|
||||
uses the expected schedule; separate tiers still replace sequences wholesale.
|
||||
Test same-label distinct native namespaces and copies of one namespace. NoSource
|
||||
still contributes no source or explicit empty root.
|
||||
|
||||
## Stage 8 — Define private defaults and the final declaration parser
|
||||
|
||||
Add the private defaults snapshot/validation and resolved-policy helpers. Add
|
||||
the final declaration parser as an unwired private helper until Stage 14; retain
|
||||
the current wired parser only until that cutover. Store declaration paths and
|
||||
field locations for exact diagnostics and later no-selection evidence.
|
||||
|
||||
Cover the roadmap's selector/option matrix: scalar/list normalization, exactly
|
||||
one selector, unknown fields including removed `optional`, null/wrong-type
|
||||
members, empty lists, duplicates, wildcard validation, literal destinations,
|
||||
placement, and effective-recursion/depth applicability. Parse all declarations
|
||||
before selecting candidates; invalid inactive fields still fail.
|
||||
|
||||
Acceptance: parser/policy tests cover omitted, explicit false, explicit empty,
|
||||
application defaults, and invalid default patterns without source access. No
|
||||
new YAML syntax is accepted by public loading yet.
|
||||
|
||||
## Stage 9 — Implement named-file selection and exclusions
|
||||
|
||||
Build a private selector result containing normalized lexical candidates and
|
||||
selection outcome. Implement string/list `path`, local candidate deduplication,
|
||||
basename exclusions, and optional/required presence semantics. Check excluded
|
||||
required target existence without opening content. Do not treat permission,
|
||||
containment, regular-file admission, or parser failures as optional absence.
|
||||
|
||||
Keep selector results distinct from source-admission identities; no source IDs
|
||||
or read counts are assigned merely by selection. Preserve current validity rules
|
||||
for explicit paths and existing source-access behavior for named symlinks and
|
||||
hidden targets. Do not apply search-only controls to this selector.
|
||||
|
||||
Acceptance: temporary-file tests cover partial missing lists, required/excluded
|
||||
missing targets, explicit empty lists, alias candidates, and unread excluded
|
||||
content. No fake source records are created for absence.
|
||||
|
||||
## Stage 10 — Implement shallow directory selection
|
||||
|
||||
Add literal directory string/list search, scalar/list basename patterns, and
|
||||
exclusions through the same candidate-selection result. Start with nonrecursive
|
||||
selection. Missing roots contribute nothing; an inaccessible or invalid supplied
|
||||
root is not absence. Directories are traversal containers, not documents.
|
||||
|
||||
Implement set union and difference, normalized candidate-path deduplication,
|
||||
and requiredness across the complete selected union. Preserve nil/unrestricted
|
||||
versus explicit-empty patterns and alias spelling during filtering. Test multiple
|
||||
roots, overlapping roots/patterns, extensionless and hidden filenames, and a
|
||||
missing root alongside one that supplies the required match.
|
||||
|
||||
Acceptance: shallow directory tests pass with actual host files and a native
|
||||
filesystem; no per-root/per-pattern requiredness is introduced.
|
||||
|
||||
## Stage 11 — Add recursive directory traversal and depth accounting
|
||||
|
||||
Extend the walker with explicit traversal frames, effective recursion, and the
|
||||
settled depth convention. Apply filename patterns only to files, never to prune
|
||||
directories. Share bounded directory-reading and entry accounting with glob
|
||||
discovery. Do not rescan a root per pattern or use the import-edge depth limit
|
||||
as a directory-recursion limit.
|
||||
|
||||
Acceptance: direct files are depth 1, depth 2 includes one descendant level,
|
||||
zero/omission are unlimited subject to existing budgets, and depth requires
|
||||
effective recursion. Cover application-enabled recursion, explicit false,
|
||||
large depth integers, empty searches, and limits using test-controlled budgets.
|
||||
|
||||
## Stage 12 — Add discovery symlink and hidden controls
|
||||
|
||||
Implement `follow`/`hidden` for directory discovery using capability-aware
|
||||
filesystem helpers. Explicit roots keep existing access semantics; discovered
|
||||
hidden directories prune when hidden is false, discovered symlink directories
|
||||
do not descend when follow is false, and analogous files are not selected.
|
||||
|
||||
When following links, track active-path directory identities and fail actual
|
||||
loops without treating earlier completed branches as cycles. Preserve namespace
|
||||
containment and candidate spellings. Cover contained links, escapes, filename
|
||||
filtering on aliases, self/ancestor loops, and separate noncyclic aliases that
|
||||
later retain ordinary repeated-source admission behavior.
|
||||
|
||||
Acceptance: host filesystem behavior and a focused link-aware native fixture
|
||||
pass; plain native filesystems still load without new capability requirements.
|
||||
All success/failure paths close library-owned directory and root handles.
|
||||
|
||||
## Stage 13 — Integrate glob filtering and final candidate accounting
|
||||
|
||||
Adapt `glob.go` to the common selection pipeline. Keep path wildcards and
|
||||
literal components distinct so follow/hidden filters affect only wildcard-
|
||||
discovered entries, not explicitly named components. Apply basename exclusions
|
||||
to final candidates. Preserve regular-file/source validity behavior rather than
|
||||
silently accepting invalid glob-selected sources.
|
||||
|
||||
Move source-allowance checking after exclusions and declaration-local
|
||||
deduplication. Intermediate traversal candidates are bounded by entry visits,
|
||||
not by the final source allowance. Charge bytes only when selected content is
|
||||
read; never read excluded content. A tiny private source limit with many excluded
|
||||
positive matches must succeed when its final selected set fits.
|
||||
|
||||
Acceptance: existing glob syntax, containment, alias, and visit-budget tests
|
||||
pass alongside discovery-control and post-filter source-limit regressions.
|
||||
|
||||
## Stage 14 — Wire final syntax and load-wide defaults through the engine
|
||||
|
||||
Add the private defaults value to ordinary/grouped requests, snapshot/validate
|
||||
it before acquisition, and pass it to every enabled main/underlay/import
|
||||
declaration. Wire Stage 8's parser and Stages 9–13's selection pipeline into
|
||||
graph acquisition. Remove the old declaration parser and `optional` field;
|
||||
there is one final parser and one absence policy.
|
||||
|
||||
Include `source_version.go`'s stored import declarations in this wiring: syntax
|
||||
parsing stays independent of source-version interpretation, and every stored
|
||||
declaration receives the same effective policy before discovery. Do not bypass
|
||||
validation when a consumed header or empty payload leaves no application fields.
|
||||
|
||||
Keep imports disabled unless already enabled by the consumer. Selected overlays
|
||||
still cannot enable their own imports; defaults do not change that boundary.
|
||||
Validate effective placement/depth and declaration values before relying on a
|
||||
missing target or empty selection to skip work. Declarations do not inherit
|
||||
parent control values.
|
||||
|
||||
Migrate existing tests and maintained fixture declarations from `optional` to
|
||||
the intended `required` behavior. Tests expecting a missing import to fail must
|
||||
request requiredness, not weaken their checks. Update the owning configuration
|
||||
contract to describe the now-implemented final YAML interface and breaking
|
||||
absence/order changes. Keep exact public Go defaults documentation for Stage 16.
|
||||
|
||||
Acceptance: all engine imports, glob, destinations, source-version, and layered
|
||||
tests pass under final syntax. An explicit regression rejects `optional`;
|
||||
another proves missing imports are optional without setup. Run everyday checks.
|
||||
|
||||
## Stage 15 — Retain no-selection evidence across load outcomes
|
||||
|
||||
Add the private records from the settled inspection design to declaring source
|
||||
records and their clone functions. Record only completed, optional, whole-
|
||||
declaration empty outcomes. Preserve evidence for main and imported declarations
|
||||
and underlay inputs through composition, nested item placement, overlays,
|
||||
resolution entry state, final publication, and failed-load accumulation.
|
||||
|
||||
Use source IDs to attach outcomes, not scheduled positions. Reuse source-record
|
||||
transport; do not add synthetic imported sources or warnings. Keep evidence
|
||||
source-local and detached even when its source destination remains unresolved.
|
||||
|
||||
Acceptance: tests cover no matches, missing paths, empty lists, exclusions,
|
||||
partial path-list omission (no record), and required empty paths (no record).
|
||||
An error after a prior empty optional declaration retains that established
|
||||
evidence, but does not fabricate later outcomes. Mutating query results cannot
|
||||
alter subsequent snapshots or another load.
|
||||
|
||||
## Stage 16 — Expose defaults and inspection through the public facade
|
||||
|
||||
Add root-owned declarations from this plan, `ImportDefaults` fields on ordinary
|
||||
and layered options, and `SourceInfo.ImportSelections`. Add explicit converters
|
||||
and engine transport types/helpers as needed, following existing root-wrapper
|
||||
ownership. Snapshot pointers/slices and preserve nil versus non-nil empty
|
||||
patterns. Do not add defaults on individual inputs or a new result query API.
|
||||
|
||||
Exercise final behavior through `Load` and `LoadLayered`, including defaults
|
||||
applied to transitive and underlay imports, explicit declaration exceptions,
|
||||
invalid default preflight without reader consumption, and result/error/resolver
|
||||
source inspection ownership. Update declaration comments and the owning Go API
|
||||
guidance when the surface becomes available.
|
||||
|
||||
Acceptance: public facade/import-boundary tests and representative engine/public
|
||||
equivalence cases pass; no internal type leaks through exported signatures.
|
||||
|
||||
## Stage 17 — Audit cross-feature lifecycle and ownership
|
||||
|
||||
Review and fill meaningful gaps rather than adding a full Cartesian-product
|
||||
suite. Reuse existing regressions for version protection, consumed-header
|
||||
sensitivity, scope diagnostics, NoSource, and historical removed descendants.
|
||||
|
||||
Add representative combined cases for scheduled discovered items with helper-
|
||||
supplied IDs; nested destinations and actual assigned indexes; required versus
|
||||
if-present source versions; main-version ownership after main moves later in a
|
||||
schedule; inherited relative resources; superseded relationships; and final
|
||||
configuration/metadata/explanation agreement. Ensure consumed headers cannot
|
||||
silently supply record IDs and secret values remain absent from diagnostics
|
||||
and inspection. Preserve callback phases and source-local callback ordering.
|
||||
|
||||
Compare an equivalent keyed graph through import and inheritance integrations:
|
||||
both use the scheduler's eligible-node rule despite different domain operations.
|
||||
Keep acquisition-source records stable when only graph construction order is
|
||||
permuted in private scheduler/integration fixtures; do not promise unchanged IDs
|
||||
when authored discovery order itself changes.
|
||||
|
||||
Acceptance: run `go test -race ./internal/engine`, focused root facade tests,
|
||||
and everyday checks. Record any genuine unresolved gap before marking complete.
|
||||
|
||||
## Stage 18 — Maintain simple and complex consumer examples
|
||||
|
||||
Update the prompt-catalog example for directory search, multiple patterns,
|
||||
exclusions, and helper-supplied IDs while retaining explicit registration and
|
||||
application final validation. Include application import defaults and a
|
||||
declaration exception, plus inspection of a deliberately empty optional search.
|
||||
Keep a short simple single-file/required-file example so adoption does not
|
||||
require understanding all discovery controls.
|
||||
|
||||
Update fixture expectations for scheduled sequence positions. Verify mounted
|
||||
resource origins, whole-sequence precedence, and quiet absence through executable
|
||||
examples. Do not add a consumer-side discovery, merge, scheduling, or provenance
|
||||
reconstruction pass. All fixtures remain local, deterministic, and secret-free.
|
||||
|
||||
Acceptance: consumer tests and executable public examples pass; the consumer
|
||||
guide links complete copyable examples rather than duplicating them.
|
||||
|
||||
## Stage 19 — Finalize documentation and validate the completed unit
|
||||
|
||||
Align README orientation, `docs/config.md`, public declaration comments,
|
||||
`docs/internal/overview.md`, relevant focused internal docs, and the development
|
||||
reading/test map. Document Kahn's algorithm, set union/difference, and active-path
|
||||
cycle detection beside their owners. State acquisition versus resolution order,
|
||||
explicit defaults precedence, no-selection evidence, and source namespace/key
|
||||
construction without duplicating canonical contracts.
|
||||
|
||||
Update architecture policy to recognize implemented explicit directory discovery
|
||||
and shared scheduling while retaining the boundary against unrequested implicit
|
||||
application-path discovery. Update only ADR status/navigation as needed to link
|
||||
implemented contracts; accepted decision text stays unchanged. Leave release
|
||||
notes/version choice and roadmap retirement for separately authorized release
|
||||
preparation. Do not introduce release gates, CI waiting, consumer validation
|
||||
requirements, dependencies, or unrelated defaults/security changes.
|
||||
|
||||
Run the everyday `./scripts/check.sh`, `go test -race ./...`, consumer/examples
|
||||
tests, local documentation links, and `git diff --check`; reuse checks already
|
||||
covering unchanged final content instead of repeating them gratuitously. Review
|
||||
the baseline-to-final public and YAML diff for removed `optional`, changed
|
||||
requiredness and sequence ordering, and accurately documented native filesystem
|
||||
capability limits. Inspect source and history indexes for accidental quadratic
|
||||
rescanning; no timing thresholds or busy-host benchmark evidence are required.
|
||||
|
||||
Acceptance: all stages are complete, the final implemented behavior matches the
|
||||
roadmap and ADRs, validations are recorded here, and the implementation workspace
|
||||
is committed and clean. No release is published by this plan.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None required to begin implementation. The API, evidence shape, ordering keys,
|
||||
scope boundaries, and cycle treatment are selected above. Private helper names
|
||||
and file splits may be adjusted for clarity without changing those decisions.
|
||||
If implementation reveals a genuine conflict between an accepted requirement
|
||||
and existing contracts, report it rather than silently strengthening or weakening
|
||||
either one.
|
||||
Reference in New Issue
Block a user