Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions packages/configorama/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3458,3 +3458,34 @@ Bug reports and reproductions are very welcome. Please open an [issue](https://g
- 🐛 [Report bugs](https://github.com/DavidWells/configorama/issues)
- 💡 [Request features](https://github.com/DavidWells/configorama/issues)
- 📖 [Read the docs](https://github.com/DavidWells/configorama#readme)


### Resolver reliability settings

Each load snapshots cwd, environment and options. For concurrent callers, use
`dotEnvMode: 'isolated'` to keep dotenv values local; the default `'process'`
retains the existing process.env mutation. `moduleCacheMode: 'load'` evaluates a
fresh config-owned JS/TS/MJS dependency graph per load. `'process'` shares that
graph across calls; `'legacy'` retains existing format-specific defaults.

Async resolution accepts `timeoutMs` and an AbortSignal as `signal`. Deadlines
start at API entry and are cooperative. `resolutionLimits` controls maxPasses
(default 1000), maxDepth (512), and maxVisitedNodes (1000000). Sync supports the
same deadline and work bounds but rejects a live AbortSignal.

The sync API preserves undefined, BigInt, Dates, RegExp state, sparse arrays,
null-prototype objects and shared acyclic aliases. Unsupported values, accessors
and cycles produce structured path errors. Literal strings that resemble private
markers and own keys such as `__proto__` are data. Markdown preserves existing
frontmatter keys and selects the first free body key.

Inspection adds authored occurrences and `defaultAvailability`:
`'guaranteed'`, `'conditional'`, or `'none'`. A variable/file fallback or an
error-capable filter is conditional even if the legacy requirements view reports
it optional. Graph/audit report possible branches without executing them.
Relative dynamic file targets retain their authored file's directory; aliases,
overrides and safe-root checks apply to the selected target.

[Detailed contracts and migration guidance](docs/testing/resolver-reliability.md)
include the supported limitations and regression owners. Library diagnostics go
to stderr so JSON output and configx shell exports remain usable in pipelines.
605 changes: 605 additions & 0 deletions packages/configorama/docs/plans/resolver-reliability-2026-10.md

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions packages/configorama/docs/testing/expression-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Shared expression syntax

The scanner reads source text without resolving values or invoking plugins. Offsets are UTF-16 indexes into the original string, with exclusive ends. Nodes have stable integer IDs and parent IDs, raw source, kind and complete status. Parent IDs avoid cyclic objects. The result and its node/diagnostic arrays are immutable. A configured prefix/suffix defines the wrapper independently of environment or options; matching quotes follow odd/even backslash escape rules after the file format has already decoded its own lexical escapes.

Reference nodes retain all nested references, including references in quoted composition. A reference owns its top-level comma fallback slots and single-pipe filters; `||`, quoted delimiters and delimiters inside nested wrappers, calls, arrays or objects do not split it. Call nodes retain balanced parentheses and argument boundaries. Literal, composition, argument, fallback and filter projections refer to the same original spans. File/text path arguments may contain literal braces: a consumer can choose their path projection without treating those characters as new variable wrappers. Text outside a variable wrapper, including VTL calls, remains caller-owned text in the preprocessing projection.

`${env:X}` is a reference even if X is absent. `${env:X, "sl-${sls:stage}"}` includes a quoted composition with a nested reference; source ownership decides whether that reference resolves. `${merge("foo()", "x")}` has two literal arguments and no call inside the quoted string. `#set($m = {"x": 1})` is external code unless its owner explicitly asks for call discovery.

Malformed fragments retain their original spans and produce sanitized diagnostics rather than fabricated values. Scanner visits and active syntax depth count toward the load's existing deterministic budgets. Resolution owns value types, lazy fallback selection, filters, recognized sources and ignore-path policy. Preprocessing owns projections that protect literal characters and JSON arguments. Metadata/static discovery owns an occurrence projection, never another evaluator. The shared ownership matrix in `tests/reliability/ownershipCorpus.js` is the compatibility source for all three consumers. Public lookup grammar is unchanged.

Identical source/wrapper scans reuse immutable nodes within one load. Each lookup
still checks the load budget; different syntax protection settings use separate
entries. This keeps ordinary long fallback lists within the default work bound
without sharing syntax state across callers or raising the limits.
7 changes: 7 additions & 0 deletions packages/configorama/docs/testing/file-origins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Relative reference origins

A file/text expression is authored by the file that supplied its value. Raw object input uses the configured root directory. Dynamic selectors resolve before choosing a path. For ordinary relative paths, an existing target beside the author wins; otherwise retain the root-directory and existing find-up search. Absolute and home paths select their explicit target. TypeScript/JavaScript aliases resolve through the root's existing tsconfig/jsconfig mappings. An explicit filePathOverrides match against the requested path wins over all of these selections and its relative target uses the root directory.

Keep the requested spelling and selected lexical path for diagnostics. Use realpath for cache, dependency-cycle and security identity. Safety checks run on the final selected target after aliases, overrides and origin preference, including symlink boundaries. Internal provenance records use structural path identity and carry authored file, root, requested path, selected lexical target, canonical target and selection reason. The resolver registers the origin of expanded containers and follows it through nested references and self aliases; syntax substitution does not rewrite the caller's literals.

Legacy root/find-up fallback remains available when no authored sibling exists. This preserves existing shared-file layouts while resolving static and dynamic sibling paths consistently. Executable config exports follow the same origin rules as parsed JSON/YAML/TOML values. text() remains opaque; deployment raw file() inlining keeps its established known-reference substitution and foreign-reference passthrough.
39 changes: 39 additions & 0 deletions packages/configorama/docs/testing/inspection-reliability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Inspection and runtime provenance

`analyze` reports the authored expression's complete reference occurrences. Each
occurrence retains UTF-16 start/end spans, its raw reference, parent node,
annotation role, ownership, filters, path segments and reversible path identity.
Its occurrence ID encodes the path identity and spans; equal text at different
config destinations remains distinct. Discovery uses declared prefixes and regex
source descriptors. It does not invoke custom matcher, resolver, function or
filter callbacks. Executable root configs retain their existing loading rules;
safe inspection blocks those entry points.

`discovery: 'static-possible'` describes a dependency that might be used.
`defaultAvailability` is `guaranteed` for a syntactic literal fallback without
filters, `conditional` for dynamic/variable/file fallbacks or filters, and `none`
when there is no fallback. These additive fields accompany the existing default,
required and type fields. A legacy optional classification does not promise that
a conditional default will resolve or that a filter cannot throw. Inspection
does not execute a filter to establish its output type.

For example `${env:X, "literal"}` has a guaranteed default;
`${env:X, env:Y}` and `${env:X, file(missing.yml)}` are conditional.
`${env:X, "literal" | Number}` remains conditional because conversion can fail.
Graph `possible` edges carry occurrence identity and item position. Audit retains
possible executable/file dependencies, including a bare fallback call, even when
an earlier runtime branch would win. Dynamic file targets produce partial-edge
diagnostics; inspection does not run code to discover their targets.

With returnMetadata, runtime fallback selections record selected, skipped and
missing slots. Authored occurrences carry the selected branch when it can be
matched to that execution record. Other runtime outcomes are `unobserved`; static
analysis alone reports `unknown`. Rewritten references are not given invented
execution results. `fileDependencies.selectedReferences` separately records real
runtime file selections, authored origin, lexical/canonical target and selection
reason. Static fileDependencies describe possible reads.

`tests/reliability/inspection.test.js` checks custom wrappers, original spans,
separate destinations, conditional defaults, branch risks, runtime choices and
real CLI/API non-execution sentinels. The conformance graph golden intentionally
adds occurrence-specific possible edges; deployment output goldens remain exact.
58 changes: 58 additions & 0 deletions packages/configorama/docs/testing/resolver-reliability-coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Resolver reliability coverage and evidence

Baseline: configorama 1.4.9 at aebe1f51f4da6274da255861ae05393e17f0d1a8, rechecked against the current worktree. Concurrent sls:stage support changes were observed during the baseline and are preserved; ownership cases must distinguish that newly known source from foreign names.

Run `node scripts/reliability-probes.js --survey` for the complete desired-contract inventory, or select a case by name to require success. All twelve baseline failures now pass. `TEST_VERBOSE=1` includes synthetic diagnostic evidence. Each case runs in a bounded owned process group, including cleanup of its sync worker. This inventory is not registered as skipped or expected-failing normal tests; each completed fix adds its passing normal regressions.

| Case | Owner task | Required behavior | Baseline |
|---|---|---|---|
| `filter-special-keys` | 3.1 | Every filtered own key contains HELLO | fail |
| `runtime-object-marker` | 2.1 | Reference retains complete user record without mutation | fail |
| `private-character` | 2.2 | Literal U+E001 stays exact | fail |
| `sync-date-marker` | 6.3 | Date-looking dictionary stays a dictionary | fail |
| `sync-undefined` | 6.3 | Explicit undefined own key survives sync | fail |
| `sync-bigint` | 6.3 | BigInt retains type and value | fail |
| `markdown-own-key` | 3.2 | Own hasOwnProperty frontmatter works | fail |
| `markdown-body-collision` | 3.2 | All frontmatter keys survive body insertion | fail |
| `structure-cycle` | 7.1 | YAML alias cycle reports controlled error | fail |
| `module-load-refresh` | 5.3 | Explicit load mode refreshes JS/TS/MJS | fail |
| `dotenv-root` | 5.2 | Dotenv comes from config root | fail |
| `dotenv-stdout` | 12.1 | Dependency progress emits no stdout | fail |

## Existing compatibility gates

- Fallback/quoted passthrough/partial items: tests/fallbackPartialItem, tests/passthroughInFallback and tests/fallbackSlotValues.
- Deployment code contexts and byte-exact outputs: tests/serverlessGoldens; concurrent sls updates change stage ownership and are tested at the new source boundary.
- Format/parsing/key safety: tests/parserEdgeCases, tests/coverageGaps and tests/fuzz/properties/structures.js.
- Marker authenticity: tests/fuzz/properties/markers.js plus new object/private-character cases above.
- Sync sources and transport: tests/syncFactory, tests/syncEnv, tests/syncApi and tests/metadata/sync-metadata.test.js.
- File roots, cycles and safe mode: tests/fileValues, tests/pathologicalCases, tests/security.
- Output channels: tests/stdoutHygiene and CLI/configx consumer tests.

## Contract decisions

Read the workstream contract in docs/plans/resolver-reliability-2026-10.md or its self-contained bead. Preserve 1.x dotenv process mutation with named process/isolated modes; preserve legacy module format defaults with explicit process/load modes. Sync values require collision-safe transport, path-aware rejection and projected source factories. Parser nodes remain lexical independently of missing values; static inspection reports possible branches without executing them. Each task supplies direct expected values/types/own keys and its regression owner. All twelve approved ideas are covered by the plan and existing/new test ownership; independent oracle/runtime/performance initiatives 13-15 remain excluded.


## Completed regression ownership

| Ideas | Normal gate |
|---|---|
| 1 cross-feature generation | tests/fuzz/properties/crossFeature.js; tests/reliability/harness.test.js |
| 2 private records/text | tests/reliability/runtimeRecords.test.js; opaqueText.test.js |
| 3 own dictionaries/Markdown | dictionaries.test.js; markdownKeys.test.js |
| 4 shared grammar | src/utils/expressions/scan.test.js; expressionRuntime.test.js |
| 5 load state/module lifecycle | loadContext.test.js; moduleLoader.test.js; moduleLifecycle.test.js |
| 6 sync transport | src/utils/encoders/transport.test.js; syncTransport.test.js |
| 7 bounded work | resolutionBounds.test.js; structureCycles.test.js; harness.test.js |
| 8 ownership | ownershipCorpus.test.js; ownership.test.js; unchanged deployment goldens |
| 9 authored origin | fileOrigins.test.js; tests/fileRefPaths/fileRefPaths.test.js |
| 10 path identity | pathIdentity.test.js; src/utils/paths/pathIdentity.test.js |
| 11 inspection agreement | inspection.test.js; tests/conformance/conformance.test.js |
| 12 output channels | diagnostics.test.js; tests/stdoutHygiene/stdoutHygiene.test.js; configx shell tests |

Names without a directory in the table belong to tests/reliability. The baseline
column above records historical failures; it is not an expected-failure allowance.
The pairwise gate requires complete pair coverage, and the generated property runs
under the same fixed/fresh seed watchdog as every other property. No baseline case
is skipped or marked expected-failing.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Resolver reliability verification — 2026-10-02

All twelve approved improvements are implemented under the 55-bead plan.
The original twelve failure probes now pass. Normal tests include the shared
parser, ownership, dictionary, path, transport, origin, inspection and diagnostic
regressions; no new skipped or expected-failure cases were introduced.

## Final checks

- Root `pnpm -r --if-present typecheck`: passed.
- Root `pnpm test`: passed across the monorepo, including configx. Configorama
reports 853 passing library tests and 1762 passing main tests; existing optional
skips remain. Slow tests and other package suites also pass.
- Configorama `npm run types`: passed; declaration generation is publishable.
- `TEST_VERBOSE=1 npm run fuzz`: all 12 properties passed at 2000 cases each,
24,000 fresh-seed cases total, in 200 seconds.
- `node scripts/reliability-probes.js`: all 12 baseline probes passed.
- Deterministic covering array: 19 strata, zero missing axis pairs.
- Deployment goldens: all 12 passed without output changes. The inspection graph
golden adds two reviewed possible edges with authored occurrence IDs; existing
audit goldens remain unchanged.
- `git diff --check`: passed. Source AST diagnostic audit passed; CLI/display
presentation and captured HCL child JSON transport are the explicit boundaries.
- Bead dependency cycle check: zero cycles. Recovery backups from the earlier
tracker repair are preserved; database integrity and JSONL consistency pass.

## Fresh-seed replay

Each row ran 2000 cases. Use `FUZZ_RUNS=2000 FUZZ_ONLY="<property>" FUZZ_SEED=<seed>
node tests/fuzz/fuzz.test.js`; append FUZZ_PATH from a failure to replay its
shrunk case. Successful seed logs were retained with TEST_VERBOSE=1.

| Property | Seed |
|---|---|
| cross-feature recursive expressions | -25989768 |
| encoder round-trips | -116139093 |
| slot transparency | -1432869455 |
| lazy fallbacks | -896651152 |
| no crashes | -114905767 |
| filters after fallbacks | -432025576 |
| key paths | -1543989295 |
| internal markers | -992486689 |
| unknown names | -368057960 |
| equivalence | -2128382376 |
| custom syntax | -1263996722 |
| structure preservation | -1520431571 |

## Supported limits and migration

[Resolver reliability contracts](resolver-reliability.md) document defaults,
opt-in isolated dotenv and fresh module graphs, typed sync transport, cooperative
limits/cancellation, data authenticity and diagnostic channels.
[Inspection guidance](inspection-reliability.md) distinguishes static possibilities,
conditional defaults and actual selected/skipped runtime branches.
[File origins](file-origins.md) documents directory precedence and canonical safety.
[Coverage ownership](resolver-reliability-coverage.md) maps all twelve ideas to
normal regressions and compatibility gates.

The implementation is committed locally on `feat/resolve-sls-stage` in a logical
series covering shared infrastructure, runtime integration, fuzz coverage and
documentation. No release, version bump or push was performed.
Loading
Loading