Skip to content

Commit 781fd71

Browse files
authored
feat(deploy): Terraform property-graph mode parity (issue #286, PR 4) (#291)
Match the bash deploy's schema-derived mode in the Terraform module so the two surfaces expose the same artifact-mode contract. - New variable property_graph (bool, default false). When true, the module sets BQAA_PROPERTY_GRAPH=property_graph.sql on the Cloud Run Job, so the #289 runtime derives the ontology+binding (targeting the graph dataset via the #288 enabler) instead of an explicit ontology/binding pair. The published image must be built with build_image.sh --property-graph (PR 3) so the placeholdered property_graph.sql + table_ddl.sql are staged. - Plan-time precondition rejects property_graph=true + extraction_mode= compiled-only, mirroring the bash deploy's boundary rejection (derived mode stages no reference extractors). - Explicit ontology/binding (compiled-extractor) path unchanged when property_graph=false. terraform.tfvars.example documents the new toggle. terraform validate passes; terraform fmt clean. Tests: static assertions pin the variable, the conditional BQAA_PROPERTY_GRAPH env wiring, and the compiled-only precondition (so bash + TF can't drift), plus a terraform fmt gate. 12 tests pass. Next (PR 5): deploy README + Terraform README docs.
1 parent 9127ba1 commit 781fd71

4 files changed

Lines changed: 103 additions & 0 deletions

File tree

examples/migration_v5/periodic_materialization/terraform/main.tf

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ locals {
6666
var.extraction_mode == "compiled-only" ? {
6767
BQAA_REFERENCE_EXTRACTORS_MODULE = "reference_extractor"
6868
} : {},
69+
# Schema-derived mode (#286): tell the runtime to derive the spec from the
70+
# staged ``property_graph.sql`` instead of the explicit ontology/binding
71+
# pair. Mirrors the bash deploy's ``BQAA_PROPERTY_GRAPH`` wiring.
72+
var.property_graph ? {
73+
BQAA_PROPERTY_GRAPH = "property_graph.sql"
74+
} : {},
6975
)
7076
}
7177

@@ -268,6 +274,16 @@ resource "google_cloud_run_v2_job" "periodic" {
268274
}
269275
}
270276

277+
# Schema-derived mode has no reference extractors staged, so
278+
# ``compiled-only`` would empty_extract at runtime. Reject the
279+
# combination at plan time, mirroring the bash deploy's boundary check.
280+
lifecycle {
281+
precondition {
282+
condition = !(var.property_graph && var.extraction_mode == "compiled-only")
283+
error_message = "property_graph = true (schema-derived mode) does not support extraction_mode = \"compiled-only\": no reference extractors are staged in derived mode. Use \"ai-fallback\", or the explicit ontology/binding path."
284+
}
285+
}
286+
271287
# Allow IAM bindings on the runtime SA to settle before the
272288
# Cloud Run Job starts. Same race the bash deploy's
273289
# ``_retry_iam`` defends against — Terraform's dependency

examples/migration_v5/periodic_materialization/terraform/terraform.tfvars.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ image_uri = "us-central1-docker.pkg.dev/your-project/bqaa/periodic-mater
1515
# Optional overrides (commented = use the default)
1616
# location = "US"
1717
# job_name = "bqaa-periodic-materialization"
18+
# property_graph = false # true → schema-derived mode (no ontology/binding);
19+
# # build the image with build_image.sh --property-graph;
20+
# # not compatible with extraction_mode = "compiled-only"
1821
# extraction_mode = "ai-fallback" # or "compiled-only"
1922
# max_retries = 2
2023
# max_session_age_hours = 24 # null → orphan watchdog disabled

examples/migration_v5/periodic_materialization/terraform/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ variable "extraction_mode" {
7474
}
7575
}
7676

77+
variable "property_graph" {
78+
description = "Schema-derived mode (#286). When ``true``, the runtime derives the ontology + binding from a staged ``property_graph.sql`` + the table schemas instead of an explicit ``ontology.yaml`` / ``binding.yaml`` pair (the module sets ``BQAA_PROPERTY_GRAPH=property_graph.sql``). The published image must be built with ``build_image.sh --property-graph`` so the placeholdered (``$${PROJECT_ID}`` / ``$${DATASET}``) ``property_graph.sql`` + ``table_ddl.sql`` are staged. Use for rename-free graphs; not compatible with ``extraction_mode = \"compiled-only\"`` (no reference extractors are staged in derived mode). ``false`` (default) = explicit ontology + binding (the migration-v5 / compiled-extractor path)."
79+
type = bool
80+
default = false
81+
}
82+
7783
variable "max_retries" {
7884
description = "Cloud Run Job retry count on failure. The orchestrator's session-level idempotency + append-only state table make additional retries safe. Default 2 matches the deploy script post-#183 (production posture: silently absorb transient BQ slot pressure / rate-limit noise instead of paging on-call)."
7985
type = number
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Terraform property-graph parity: variable + env + guard wiring (issue #286).
16+
17+
Static assertions on the HCL pin the same contract the bash deploy exposes (so
18+
the two surfaces don't drift), plus a ``terraform fmt`` gate when the binary is
19+
available (no provider download / network needed). Full ``terraform validate``
20+
is exercised locally during development; it needs provider init and is left out
21+
of CI to stay offline-safe.
22+
"""
23+
24+
from __future__ import annotations
25+
26+
from pathlib import Path
27+
import shutil
28+
import subprocess
29+
30+
import pytest
31+
32+
_TF_DIR = (
33+
Path(__file__).resolve().parents[1]
34+
/ "examples"
35+
/ "migration_v5"
36+
/ "periodic_materialization"
37+
/ "terraform"
38+
)
39+
_MAIN = (_TF_DIR / "main.tf").read_text()
40+
_VARS = (_TF_DIR / "variables.tf").read_text()
41+
_TFVARS = (_TF_DIR / "terraform.tfvars.example").read_text()
42+
43+
44+
def test_property_graph_variable_declared() -> None:
45+
assert 'variable "property_graph"' in _VARS
46+
assert "type = bool" in _VARS
47+
48+
49+
def test_env_var_wired_conditionally() -> None:
50+
# BQAA_PROPERTY_GRAPH is set only when var.property_graph is true.
51+
assert "var.property_graph ?" in _MAIN
52+
assert 'BQAA_PROPERTY_GRAPH = "property_graph.sql"' in _MAIN
53+
54+
55+
def test_compiled_only_precondition() -> None:
56+
# Plan-time guard mirrors the bash deploy boundary rejection.
57+
assert "precondition" in _MAIN
58+
assert (
59+
'!(var.property_graph && var.extraction_mode == "compiled-only")' in _MAIN
60+
)
61+
62+
63+
def test_tfvars_example_documents_property_graph() -> None:
64+
assert "property_graph" in _TFVARS
65+
66+
67+
@pytest.mark.skipif(
68+
shutil.which("terraform") is None, reason="terraform binary not available"
69+
)
70+
def test_terraform_fmt_clean() -> None:
71+
result = subprocess.run(
72+
["terraform", "fmt", "-check", "-recursive"],
73+
cwd=str(_TF_DIR),
74+
capture_output=True,
75+
text=True,
76+
timeout=60,
77+
)
78+
assert result.returncode == 0, f"terraform fmt would change:\n{result.stdout}"

0 commit comments

Comments
 (0)