Problem
app/overlay/expand_replication.py renders per-team templates by reading them from node.config (config.bridge_template, config.cidr_template, config.vlan_template, config.name_template). But the canonical schema (range42.schema.json $defs.Node) defines these as node-level fields:
bridge_template — node level
cidr_template — node level
vlan_tag — node level (note: schema uses vlan_tag, the code reads vlan_template)
Consequence: for a per_team network node authored per the canonical schema (template fields at node level), _apply_offsets never finds them in config, so they pass through unrendered — per-team bridge/CIDR/VLAN templating silently no-ops, and every team shares the same value.
This affects the compose/validate preview path only (/v1/projects/{id}/compose), not the live deploy path (which derives bridges/IPs in inventory_writer + the playbook filter plugins). But it means the preview's expanded document diverges from the schema contract.
Affected code
range42-backend-api/app/overlay/expand_replication.py — _apply_offsets reads cfg["bridge_template"] / cfg["cidr_template"] / cfg["vlan_template"].
range42-deployer-ui/src/overlay/expand_replication.ts — byte-identical mirror with the same drift (also reads from config).
- Shared test vectors under
range42-deployer-ui/schema/test-vectors/expand_replication/.
Fix (coordinated, TS + Python together)
- Read the template fields at node level (
node.bridge_template, node.cidr_template, node.vlan_tag) to match the canonical schema, rendering into the node-level bridge/cidr/vlan_tag (or wherever downstream expects).
- Reconcile the
vlan_template (code) vs vlan_tag (schema) naming.
- Update the byte-identical TS mirror (
expand_replication.ts) in lockstep.
- Add/adjust shared test vectors so TS and Python stay in sync.
Context
Surfaced during the deployer-ui canvas→document serializer work (deployer-ui #77). The serializer emits network template fields at node level per the schema; this drift is why those would not render in the preview. The serializer itself defers per-team template authoring to the archetype palette (#61); this issue is about the expansion operator honoring the schema's node-level placement when those fields do appear.
Problem
app/overlay/expand_replication.pyrenders per-team templates by reading them fromnode.config(config.bridge_template,config.cidr_template,config.vlan_template,config.name_template). But the canonical schema (range42.schema.json$defs.Node) defines these as node-level fields:bridge_template— node levelcidr_template— node levelvlan_tag— node level (note: schema usesvlan_tag, the code readsvlan_template)Consequence: for a
per_teamnetwork node authored per the canonical schema (template fields at node level),_apply_offsetsnever finds them inconfig, so they pass through unrendered — per-team bridge/CIDR/VLAN templating silently no-ops, and every team shares the same value.This affects the compose/validate preview path only (
/v1/projects/{id}/compose), not the live deploy path (which derives bridges/IPs ininventory_writer+ the playbook filter plugins). But it means the preview's expanded document diverges from the schema contract.Affected code
range42-backend-api/app/overlay/expand_replication.py—_apply_offsetsreadscfg["bridge_template"]/cfg["cidr_template"]/cfg["vlan_template"].range42-deployer-ui/src/overlay/expand_replication.ts— byte-identical mirror with the same drift (also reads fromconfig).range42-deployer-ui/schema/test-vectors/expand_replication/.Fix (coordinated, TS + Python together)
node.bridge_template,node.cidr_template,node.vlan_tag) to match the canonical schema, rendering into the node-levelbridge/cidr/vlan_tag(or wherever downstream expects).vlan_template(code) vsvlan_tag(schema) naming.expand_replication.ts) in lockstep.Context
Surfaced during the deployer-ui canvas→document serializer work (deployer-ui #77). The serializer emits network template fields at node level per the schema; this drift is why those would not render in the preview. The serializer itself defers per-team template authoring to the archetype palette (#61); this issue is about the expansion operator honoring the schema's node-level placement when those fields do appear.