Skip to content

feat: per-aspect adapter accumulation in resolve#397

Merged
vic merged 1 commit intodenful:mainfrom
sini:sf2/adapter-accumulation
Apr 8, 2026
Merged

feat: per-aspect adapter accumulation in resolve#397
vic merged 1 commit intodenful:mainfrom
sini:sf2/adapter-accumulation

Conversation

@sini
Copy link
Copy Markdown
Collaborator

@sini sini commented Apr 8, 2026

Aspects can declare meta.adapter (typed nullOr functionTo raw) to compose into resolution for their subtree. resolve's go function accumulates aspect-level adapters as it descends, composing them with the inherited adapter.

Comment thread nix/lib/aspects/types.nix Outdated
Comment thread nix/lib/aspects/resolve.nix Outdated
@sini sini force-pushed the sf2/adapter-accumulation branch from ddca3c7 to ccd0ace Compare April 8, 2026 05:13
@sini sini requested a review from vic April 8, 2026 05:25
Comment thread nix/lib/aspects/resolve.nix Outdated
@sini sini force-pushed the sf2/adapter-accumulation branch from ccd0ace to d9e711c Compare April 8, 2026 05:57
@vic vic added the allow-ci allow all CI integration tests label Apr 8, 2026
@sini sini force-pushed the sf2/adapter-accumulation branch from d9e711c to dcbc01a Compare April 8, 2026 06:16
@sini sini requested a review from vic April 8, 2026 06:18
@sini
Copy link
Copy Markdown
Collaborator Author

sini commented Apr 8, 2026

For the remaining resolve changes:
▎ resolveChild
This exposes apply to adapters so they can evaluate raw includes (which may be functions/functors). The filterIncludes adapter needs this in order to probe each include against the composed adapter before deciding whether to keep it — recurse isn't suitable since it performs a full resolve and never returns {}.

Resolve default applies the filterIncludes module because module alone doesn't act on meta.adapter, so filterIncludes is what reads it, composes the filter, probes includes, and tags survivors for propagation.

If you want I can merge it into module, or keep them as separate compositions.

vic
vic previously approved these changes Apr 8, 2026
Copy link
Copy Markdown
Member

@vic vic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! looks good.

@vic
Copy link
Copy Markdown
Member

vic commented Apr 8, 2026

Run just fmt

Adds meta.adapter option on aspects. Adapter accumulation logic lives
entirely in adapters.filterIncludes — resolve.nix stays generic,
only adding resolveChild to adapter args. Uses lastFunctionTo for
correct merge semantics.
@sini sini force-pushed the sf2/adapter-accumulation branch from dcbc01a to 40809e5 Compare April 8, 2026 06:42
@sini
Copy link
Copy Markdown
Collaborator Author

sini commented Apr 8, 2026

All clean now.

@vic
Copy link
Copy Markdown
Member

vic commented Apr 8, 2026

Awesome work @sini, you rock! 💯

@vic vic merged commit a2e7241 into denful:main Apr 8, 2026
15 checks passed
vic pushed a commit that referenced this pull request Apr 8, 2026
…#398)

Functor-producing functions in parametric.nix (applyIncludes,
deepRecurse, withOwn) carry name, __provider, and eta.adapter from self
into their return values. ctxApply also carries name and __provider on
its result.

Currently, when parametric functors evaluate, they return plain {
includes = [...]; } attrsets — losing the aspect's identity. This means
any code inspecting the resolved aspect (such as a custom adapter via
resolve.withAdapter) sees incorrect defaults instead of the original
aspect's name.

This lays groundwork for context-level adapter resolution, where
adapters declared on aspects or contexts need to propagate through the
parametric pipeline to reach forward.nix and outputs.nix. Child includes
are tagged with the parent's meta.adapter so adapters compose downward
through the include tree.

Upcoming related PRs:
- #397
- Structural provider provenance via __provider paths
- Context-level adapter on ctxApply result
- Forward/output consumption of meta.adapter
vic pushed a commit that referenced this pull request Apr 8, 2026
## Summary
- Entities automatically expose `.resolved` — the result of their
context pipeline — derived from the schema type system
- `forward.nix` defaults to `item.resolved` when `fromAspect` is absent,
enabling cross-context forwarding without manual wiring
- `mainModule` helper eliminated — entity types resolve directly via
`config.resolved`

## What changed
**options.nix** — `schemaEntryType` wraps `deferredModule` to
auto-inject `config.resolved` for any schema entry where
`den.ctx.${kind}` exists. Context args are derived from the entity's
`_module.args`, filtered to known context kinds. No per-entity
boilerplate — host, user, and home all get `.resolved` automatically.

**types.nix** — `mainModule` helper removed. Both host and home
`mainModule` options simplified to `den.lib.aspects.resolve config.class
config.resolved`.

**forward.nix** — `asp` falls back to `item.resolved or item` when
`fromAspect` is absent.

## How context adapters flow through forwards
`den.ctx.host.meta.adapter` is carried through `ctxApply` (via
`withIdentity` from #398) onto `.resolved`. When `resolve` processes it,
`adapters.filterIncludes` (from #397) picks up the adapter and applies
it transitively to the entire subtree — including nested aspects reached
through forwards.
@sini sini deleted the sf2/adapter-accumulation branch April 8, 2026 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted allow-ci allow all CI integration tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants