···11+{ den, lib, ... }:
22+let
33+ inherit (den.lib) take;
44+ inherit (den.lib.parametric) fixedTo atLeast;
55+66+ ctx.user.description = ''
77+ ## Context: den.ctx.user{host,user}
88+99+ User context stage is produced by Host for each user.
1010+1111+ This is a **continuation** of the pipeline started by `den.ctx.host`.
1212+1313+ IMPORTANT: The configuration obtained from `den.ctx.user` is provided to the Host OS level
1414+1515+ In Den, home-manager/hjem/maid are just forwarding classes that produce config at the OS
1616+ level: `home-manager.users.<alice>`, `hjem.users.<alice>`, `users.users.<alice>`, etc.
1717+1818+ A `den.ctx.user{host,user}` transitions unconditionally into `den.ctx.default{host,user}`
1919+2020+ A `den.ctx.user{host,user}` obtains OS configuration nixos/darwin by using `fixedTo{host,user} user-aspect`.
2121+ fixedTo takes:
2222+ - user-aspect's owned attrs
2323+ - static includes like { nixos.foo = ... } or ({ class, aspect-chain }: { nixos.foo = ...; })
2424+ - atLeast{host,user} parametric includes like ({ host,user }: { nixos.foo = ...; })
2525+2626+ ## Bidirectionality
2727+2828+ Battery `den.provides.bidirectional` can be included on each user that needs to take configuration from the Host.
2929+3030+ Enable per user:
3131+ den.aspects.tux.includes = [ den._.bidirectional ];
3232+3333+ Enable for all users:
3434+ den.ctx.user.includes = [ den._.bidirectional ];
3535+3636+ IMPORTANT: Enabling bidirectionality means that the following piepline is enabled:
3737+3838+ host-aspect{host} => user-aspect{host,user} => host-aspect{host,user}
3939+4040+ This means that any function at host-aspect.includes can be called:
4141+ - once when the host is obtaining its own configuration with context {host}
4242+ - once PER user that has bidirectionality enabled with context {host,user}
4343+4444+ Because of this, parametric aspects at host-aspect must be careful
4545+4646+ Instead of -in Nix both of these have the same functionArgs-
4747+4848+ ({host}: ...)
4949+5050+ or
5151+5252+ ({host, ...}: ...)
5353+5454+ Do this to prevent the function being invoked with `{host,user}`
5555+5656+ take.exactly ({host}: ...)
5757+5858+ Or this to avoid it being invoked with `{host}`
5959+6060+ take.atLeast ({host,user}: ...)
6161+6262+ Static aspects, -functions like `{class,aspect-chain}: ...`- at host-aspect.includes
6363+ have **no way** to distinguish when the calling context is `{host}` or `{host,user}` if
6464+ bidirectionality is enabled.
6565+6666+ Because of this, if you have such functions, they might produce duplicate values on list or
6767+ conflicting values on package types. A work around is to wrap them in a context-aware function:
6868+6969+ take.exactly ({host}: { includes = [ ({class, aspect-chain}: ...) ]; })
7070+7171+ '';
7272+7373+ ctx.user.into.default = lib.singleton;
7474+ ctx.user.provides.user = take.exactly from-user;
7575+ ctx.user.provides.bidirectional = take.exactly from-host;
7676+7777+ from-user = { host, user }: fixedTo { inherit host user; } den.aspects.${user.aspect};
7878+ from-host = { host, user }: atLeast den.aspects.${host.aspect} { inherit host user; };
7979+in
8080+{
8181+ den.ctx = ctx;
8282+}