Plan (optional)
Design-mode entry (designing-cldk-changes): one contract decision on the IaC Neo4j catalog. Spec: codellm-devkit/.github docs/design/specs/2026-09-02-codeanalyzer-iac-helm.md §5 (graph labels and relationships). Parent epic codellm-devkit/.github#52.
Problem
schema.neo4j.json (accepted at e127901) gives a HelmTemplate file edges to its named templates (IAC_DEFINES_TEMPLATE), template calls (IAC_HAS_TEMPLATE_CALL), and value references (IAC_HAS_VALUE_REFERENCE), but no containment edge to its HelmResourceTemplate or HelmLookupReference children. In JSON those children nest under the template's resource_templates{} / lookup_references{}, so containment is implicit; in the graph the only edge that can reach a HelmResourceTemplate is IAC_DERIVED_FROM from a rendered KubernetesResource.
Observed on DayTrader (sample.daytrader.microservices@8a68b59, chart platform/helm): the five *-service.yaml templates each hold a Service document and a {{ if .Values.ocCreateRoute }} Route document. codeanalyzer-iac attributes render provenance only for single-region files (per-region emission counts are not statically knowable through if/range), so those ten HelmResourceTemplate nodes receive no IAC_DERIVED_FROM and, lacking any containment edge, are disconnected islands in Neo4j. Every other L1 child kind has a source-side edge; these two do not.
Scope boundary
In: add two identity-only relationship types to the catalog — IAC_HAS_RESOURCE_TEMPLATE (HelmTemplate → HelmResourceTemplate) and IAC_HAS_LOOKUP_REFERENCE (HelmTemplate → HelmLookupReference) — with ownership codeanalyzer-iac, owned by the template artifact's IaC facet; extend scripts/check_iac.py edge-counterpart invariants (one edge per nested child, L1 onward, monotone); regenerate fixtures. A follow-on work item in codeanalyzer-iac (filed when picked up) copies the accepted bytes, emits the edges in internal/emit/neo4j/project.go, and adds them to the accepted-edge test helper.
Out: changing the single-region provenance rule (per-region rendering is a separate design question); any JSON shape change (resource_templates{} nesting stays).
Goals
- Every
HelmResourceTemplate and HelmLookupReference node is reachable from its template artifact in Neo4j regardless of render provenance.
- Edge counterparts are checkable by the semantic checker exactly like
IAC_HAS_VALUE_REFERENCE.
- No existing label, property, or relationship changes meaning; the change is additive.
Caveats and known risks
- The catalog is embedded byte-for-byte in
codeanalyzer-iac (internal/contract/schema.neo4j.json) and gated by make schema-check; the analyzer PR must land after the schema commit is accepted and pinned.
IAC_HAS_LOOKUP_REFERENCE has no live-corpus exercise today (neither pinned chart uses lookup); fixture coverage must come from testdata.
ttl-style naming consistency: follow the existing IAC_HAS_* pattern; do not introduce a generic CONTAINS.
Definition of done
Plan (optional)
Design-mode entry (
designing-cldk-changes): one contract decision on the IaC Neo4j catalog. Spec:codellm-devkit/.githubdocs/design/specs/2026-09-02-codeanalyzer-iac-helm.md§5 (graph labels and relationships). Parent epic codellm-devkit/.github#52.Problem
schema.neo4j.json(accepted ate127901) gives aHelmTemplatefile edges to its named templates (IAC_DEFINES_TEMPLATE), template calls (IAC_HAS_TEMPLATE_CALL), and value references (IAC_HAS_VALUE_REFERENCE), but no containment edge to itsHelmResourceTemplateorHelmLookupReferencechildren. In JSON those children nest under the template'sresource_templates{}/lookup_references{}, so containment is implicit; in the graph the only edge that can reach aHelmResourceTemplateisIAC_DERIVED_FROMfrom a renderedKubernetesResource.Observed on DayTrader (
sample.daytrader.microservices@8a68b59, chartplatform/helm): the five*-service.yamltemplates each hold aServicedocument and a{{ if .Values.ocCreateRoute }}Routedocument.codeanalyzer-iacattributes render provenance only for single-region files (per-region emission counts are not statically knowable throughif/range), so those tenHelmResourceTemplatenodes receive noIAC_DERIVED_FROMand, lacking any containment edge, are disconnected islands in Neo4j. Every other L1 child kind has a source-side edge; these two do not.Scope boundary
In: add two identity-only relationship types to the catalog —
IAC_HAS_RESOURCE_TEMPLATE(HelmTemplate→HelmResourceTemplate) andIAC_HAS_LOOKUP_REFERENCE(HelmTemplate→HelmLookupReference) — with ownershipcodeanalyzer-iac, owned by the template artifact's IaC facet; extendscripts/check_iac.pyedge-counterpart invariants (one edge per nested child, L1 onward, monotone); regenerate fixtures. A follow-on work item incodeanalyzer-iac(filed when picked up) copies the accepted bytes, emits the edges ininternal/emit/neo4j/project.go, and adds them to the accepted-edge test helper.Out: changing the single-region provenance rule (per-region rendering is a separate design question); any JSON shape change (
resource_templates{}nesting stays).Goals
HelmResourceTemplateandHelmLookupReferencenode is reachable from its template artifact in Neo4j regardless of render provenance.IAC_HAS_VALUE_REFERENCE.Caveats and known risks
codeanalyzer-iac(internal/contract/schema.neo4j.json) and gated bymake schema-check; the analyzer PR must land after the schema commit is accepted and pinned.IAC_HAS_LOOKUP_REFERENCEhas no live-corpus exercise today (neither pinned chart useslookup); fixture coverage must come fromtestdata.ttl-style naming consistency: follow the existingIAC_HAS_*pattern; do not introduce a genericCONTAINS.Definition of done
schema.neo4j.jsondeclares both relationship types withfrom/tofamilies and ownership;schema.jsonunchanged.scripts/check_iac.pyrequires exactly one counterpart edge per nestedresource_templates{}/lookup_references{}entry at L1, L2, L3, and reports the missing-edge case on a fixture.codeanalyzer-iacfollow-on work item filed and linked as a sub-issue of Epic: codeanalyzer-iac — unified IaC backend, Helm first .github#52.