feat: port entity schema to gen-schema#563
Draft
sini wants to merge 33 commits into
Draft
Conversation
6574fac to
a370d30
Compare
407bd03 to
56bbc59
Compare
Replace standalone captureWithPathsWith + resolveEntity captures with diagram.projectScope which projects the fleet capture onto scope subtrees. One fleet pipeline run, N projections — more accurate (sees full policy resolution) and more performant. Both fleet-demo and diagram-demo updated. Pin den-diagram to feat/fleet-subtree-context.
Replaces hand-rolled schemaEntryType with gen-schema mkSchemaOption. Sidecars: includes, excludes. Computed: isEntity (structural content only). Extracts resolvedCtxModule (id_hash, resolved, collisionPolicy) to _types.nix for entity type reuse. collisionPolicy flows through deferred module merge to entity instances (not a sidecar) preserving existing ctx.host.collisionPolicy resolution path.
den.hosts now accepts both forms:
- Legacy: den.hosts.x86_64-linux.igloo = { ... }
- Flat: den.hosts.igloo = { system = "x86_64-linux"; ... }
The outer option type uses a permissive submodule with deepMergeAttrs
freeformType (lib.recursiveUpdate-based merge that avoids the infinite
recursion lib.types.anything causes with cross-option references).
The apply function preprocesses flat entries into two-level form and
re-evaluates through the original attrsOf systemType, so all 6
consumers see the canonical { system.name = hostConfig } shape.
Same pattern as den.hosts: deepMergeAttrs + preprocessHosts + apply. Cross-entity host lookup and osConfig injection preserved.
Covers: id_hash, freeform, topology, meta introspection, isEntity computed, schema includes sidecar.
Update flake inputs and references to match the renamed repo at github:sini/gen-schema.
gen-schema flattened _meta into _-prefixed options and renamed sidecars → collections. nix-effects changed bindAttrs so true is a literal param, not an optionality marker — translate __args values to fx.bind.optionalArg before bind.fn.
Expose entity.aspects alongside entity.hasAspect: the flat list of all resolved aspect nodes (every depth), each the resolved node augmented with .identity (base FQN, ctx-stripped), .identityKey (full unique key incl {ctxId}), and .isNamed. Excludes the entity root and tombstoned/excluded aspects; anonymous nodes are included so callers can surface them.
One fxFullResolve per class now yields both the membership pathSet (hasAspect) and a parallel resolvedNodes state map, so the accessor adds no extra resolution beyond what hasAspect already pays. Nodes are stored behind the existing state thunk, preserving deepSeq-safety (class-content bodies are never forced by state deepSeq; reading .aspects forces only name/meta/identity).
isNamed inspects the full identity, not just the node name: isMeaningfulName misses nested anonymous instances like roles/dev/<anon>:3 (whose name slips past the exact-<anon> check), so consumers (e.g. colmena tags) can filter cleanly on .isNamed.
Adds Group K has-aspect tests: flat coverage across depths, exclude-aware, entity-root excluded, anonymous exposure, nested identity distinctness, and the named-have-clean-identity invariant.
A policy's destructured args double as a dispatch guard: `{ <kind>, ... }:`
fans the policy across every entity of that kind. There was no way to say
"fire once at my own scope, don't fan" — and naming the scope's own kind
doesn't work when that kind isn't bound in the scope's ctx. A flake-scope
resolution policy is the motivating case: `{ flake, ... }:` fails
resolveArgsSatisfied (flake isn't in its own ctx), so the policy silently
never fires — which is exactly how a stale `{ flake-system, ... }:` on
to-fleet broke the fleet→env→cluster cascade.
Add `self`: always bound in the dispatch ctx (to the scope's own context), so
`{ self, ... }:` is satisfiable and callable at any scope, and excluded from
the late-sibling fan so it fires only at its registration scope.
- dispatch.nix: inject `self` at the single dispatch chokepoint, used for both
resolveArgsSatisfied and the policy call. Backwards compatible — existing
policies use `...` and ignore the extra key.
- policy/schema.nix: drop `self`-guarded policies from the late-dispatch
fan-out so they fire once, at their own scope.
`self` is the right guard for resolution policies (to-fleet, fleet-to-envs, …)
that create children and must fire once; `{ <kind>, ... }:` stays the tool for
genuine fan-out.
Tests (self-guard): self fires at its registration scope (host OS config set);
a host-registered self policy does not fan to user children, whereas
`{ user, ... }:` fans to each.
b2bcfd4 to
1b56211
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
schemaEntryTypeinoptions.nixwith gen-schema'smkSchemaOption(sidecars:includes,excludes; computed:isEntity)_topologyand_metaintrospection from gen-schemaresolvedCtxModuleto shared_types.nixfor reuse across entity typesDetails
Schema port:
den.schemanow uses gen-schema'smkSchemaEntryTypewhich provides sidecar extraction, computed fields, and__functorwrapping. TheresolvedCtxModule(id_hash, resolved, collisionPolicy) is extracted to_types.nixand injected into entity submodule imports.Flat form: Both
den.hostsandden.homesnow accept flat declarations:A
deepMergeAttrscustom type accepts both forms, andapplypreprocesses flat entries into the canonical two-level shape viapreprocessHosts. All 6 consumers see the unchanged{ system.name = entity }shape.Tests: 18 new tests (843 total, up from 825) covering flat hosts, flat homes, id_hash, freeform attrs, topology, meta introspection, isEntity computed, and schema sidecars.
Test plan
nix develop -c just ci)default,minimal,example) unaffected