dojo.md 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/courses/GENERATION_LOG.md +20 -0
  2. package/courses/api-documentation-writing/course.yaml +12 -0
  3. package/courses/api-documentation-writing/scenarios/level-1/authentication-basics.yaml +46 -0
  4. package/courses/api-documentation-writing/scenarios/level-1/data-types-formats.yaml +45 -0
  5. package/courses/api-documentation-writing/scenarios/level-1/endpoint-description.yaml +45 -0
  6. package/courses/api-documentation-writing/scenarios/level-1/error-documentation.yaml +45 -0
  7. package/courses/api-documentation-writing/scenarios/level-1/first-documentation-shift.yaml +47 -0
  8. package/courses/api-documentation-writing/scenarios/level-1/getting-started-guide.yaml +42 -0
  9. package/courses/api-documentation-writing/scenarios/level-1/pagination-docs.yaml +51 -0
  10. package/courses/api-documentation-writing/scenarios/level-1/request-parameters.yaml +46 -0
  11. package/courses/api-documentation-writing/scenarios/level-1/request-response-examples.yaml +48 -0
  12. package/courses/api-documentation-writing/scenarios/level-1/status-codes.yaml +45 -0
  13. package/courses/api-documentation-writing/scenarios/level-2/error-patterns.yaml +48 -0
  14. package/courses/api-documentation-writing/scenarios/level-2/intermediate-documentation-shift.yaml +48 -0
  15. package/courses/api-documentation-writing/scenarios/level-2/oauth-documentation.yaml +47 -0
  16. package/courses/api-documentation-writing/scenarios/level-2/openapi-specification.yaml +46 -0
  17. package/courses/api-documentation-writing/scenarios/level-2/rate-limiting-docs.yaml +45 -0
  18. package/courses/api-documentation-writing/scenarios/level-2/request-body-schemas.yaml +46 -0
  19. package/courses/api-documentation-writing/scenarios/level-2/schema-definitions.yaml +41 -0
  20. package/courses/api-documentation-writing/scenarios/level-2/swagger-redoc-rendering.yaml +43 -0
  21. package/courses/api-documentation-writing/scenarios/level-2/validation-documentation.yaml +47 -0
  22. package/courses/api-documentation-writing/scenarios/level-2/versioning-changelog.yaml +42 -0
  23. package/courses/api-documentation-writing/scenarios/level-3/advanced-documentation-shift.yaml +43 -0
  24. package/courses/api-documentation-writing/scenarios/level-3/api-style-guide.yaml +40 -0
  25. package/courses/api-documentation-writing/scenarios/level-3/code-samples-multilang.yaml +40 -0
  26. package/courses/api-documentation-writing/scenarios/level-3/content-architecture.yaml +47 -0
  27. package/courses/api-documentation-writing/scenarios/level-3/deprecation-communication.yaml +44 -0
  28. package/courses/api-documentation-writing/scenarios/level-3/interactive-api-explorer.yaml +42 -0
  29. package/courses/api-documentation-writing/scenarios/level-3/migration-guides.yaml +42 -0
  30. package/courses/api-documentation-writing/scenarios/level-3/sdk-documentation.yaml +40 -0
  31. package/courses/api-documentation-writing/scenarios/level-3/webhook-documentation.yaml +48 -0
  32. package/courses/api-documentation-writing/scenarios/level-3/websocket-sse-docs.yaml +47 -0
  33. package/courses/api-documentation-writing/scenarios/level-4/api-changelog-management.yaml +44 -0
  34. package/courses/api-documentation-writing/scenarios/level-4/api-governance-standards.yaml +41 -0
  35. package/courses/api-documentation-writing/scenarios/level-4/api-product-strategy.yaml +41 -0
  36. package/courses/api-documentation-writing/scenarios/level-4/developer-portal-design.yaml +48 -0
  37. package/courses/api-documentation-writing/scenarios/level-4/docs-as-code.yaml +41 -0
  38. package/courses/api-documentation-writing/scenarios/level-4/documentation-localization.yaml +46 -0
  39. package/courses/api-documentation-writing/scenarios/level-4/documentation-metrics.yaml +45 -0
  40. package/courses/api-documentation-writing/scenarios/level-4/documentation-testing.yaml +41 -0
  41. package/courses/api-documentation-writing/scenarios/level-4/expert-documentation-shift.yaml +45 -0
  42. package/courses/api-documentation-writing/scenarios/level-4/multi-audience-docs.yaml +46 -0
  43. package/courses/api-documentation-writing/scenarios/level-5/ai-powered-documentation.yaml +44 -0
  44. package/courses/api-documentation-writing/scenarios/level-5/api-first-documentation.yaml +45 -0
  45. package/courses/api-documentation-writing/scenarios/level-5/api-marketplace-docs.yaml +42 -0
  46. package/courses/api-documentation-writing/scenarios/level-5/board-api-strategy.yaml +48 -0
  47. package/courses/api-documentation-writing/scenarios/level-5/documentation-program-strategy.yaml +42 -0
  48. package/courses/api-documentation-writing/scenarios/level-5/documentation-team-structure.yaml +47 -0
  49. package/courses/api-documentation-writing/scenarios/level-5/dx-competitive-advantage.yaml +46 -0
  50. package/courses/api-documentation-writing/scenarios/level-5/ecosystem-documentation.yaml +45 -0
  51. package/courses/api-documentation-writing/scenarios/level-5/industry-documentation-patterns.yaml +46 -0
  52. package/courses/api-documentation-writing/scenarios/level-5/master-documentation-shift.yaml +46 -0
  53. package/courses/code-review-feedback-writing/course.yaml +12 -0
  54. package/courses/code-review-feedback-writing/scenarios/level-1/approve-vs-request-changes.yaml +48 -0
  55. package/courses/code-review-feedback-writing/scenarios/level-1/asking-questions.yaml +50 -0
  56. package/courses/code-review-feedback-writing/scenarios/level-1/clear-comment-writing.yaml +45 -0
  57. package/courses/code-review-feedback-writing/scenarios/level-1/constructive-tone.yaml +43 -0
  58. package/courses/code-review-feedback-writing/scenarios/level-1/first-review-shift.yaml +46 -0
  59. package/courses/code-review-feedback-writing/scenarios/level-1/giving-praise.yaml +44 -0
  60. package/courses/code-review-feedback-writing/scenarios/level-1/nitpick-etiquette.yaml +44 -0
  61. package/courses/code-review-feedback-writing/scenarios/level-1/providing-context.yaml +46 -0
  62. package/courses/code-review-feedback-writing/scenarios/level-1/reviewing-small-prs.yaml +43 -0
  63. package/courses/code-review-feedback-writing/scenarios/level-1/style-vs-logic.yaml +48 -0
  64. package/courses/code-review-feedback-writing/scenarios/level-2/architectural-feedback.yaml +52 -0
  65. package/courses/code-review-feedback-writing/scenarios/level-2/intermediate-review-shift.yaml +46 -0
  66. package/courses/code-review-feedback-writing/scenarios/level-2/performance-feedback.yaml +50 -0
  67. package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-breaking-changes.yaml +44 -0
  68. package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-complex-prs.yaml +43 -0
  69. package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-documentation.yaml +47 -0
  70. package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-error-handling.yaml +50 -0
  71. package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-tests.yaml +53 -0
  72. package/courses/code-review-feedback-writing/scenarios/level-2/security-review-comments.yaml +50 -0
  73. package/courses/code-review-feedback-writing/scenarios/level-2/suggesting-alternatives.yaml +42 -0
  74. package/courses/code-review-feedback-writing/scenarios/level-3/cross-team-review.yaml +45 -0
  75. package/courses/code-review-feedback-writing/scenarios/level-3/mentoring-through-review.yaml +46 -0
  76. package/courses/code-review-feedback-writing/scenarios/level-3/reviewing-unfamiliar-code.yaml +43 -0
  77. package/courses/terraform-infrastructure-setup/scenarios/level-1/first-debugging-shift.yaml +66 -0
  78. package/courses/terraform-infrastructure-setup/scenarios/level-1/plan-output-reading.yaml +71 -0
  79. package/courses/terraform-infrastructure-setup/scenarios/level-1/resource-creation-failures.yaml +54 -0
  80. package/courses/terraform-infrastructure-setup/scenarios/level-1/resource-references.yaml +70 -0
  81. package/courses/terraform-infrastructure-setup/scenarios/level-1/state-file-basics.yaml +73 -0
  82. package/courses/terraform-infrastructure-setup/scenarios/level-1/terraform-fmt-validate.yaml +58 -0
  83. package/courses/terraform-infrastructure-setup/scenarios/level-2/count-vs-for-each.yaml +58 -0
  84. package/courses/terraform-infrastructure-setup/scenarios/level-2/dependency-management.yaml +80 -0
  85. package/courses/terraform-infrastructure-setup/scenarios/level-2/intermediate-debugging-shift.yaml +66 -0
  86. package/courses/terraform-infrastructure-setup/scenarios/level-2/lifecycle-rules.yaml +51 -0
  87. package/courses/terraform-infrastructure-setup/scenarios/level-2/locals-and-expressions.yaml +58 -0
  88. package/courses/terraform-infrastructure-setup/scenarios/level-2/module-structure.yaml +75 -0
  89. package/courses/terraform-infrastructure-setup/scenarios/level-2/provisioner-pitfalls.yaml +64 -0
  90. package/courses/terraform-infrastructure-setup/scenarios/level-2/remote-state-backend.yaml +55 -0
  91. package/courses/terraform-infrastructure-setup/scenarios/level-2/terraform-import.yaml +55 -0
  92. package/courses/terraform-infrastructure-setup/scenarios/level-2/workspace-management.yaml +51 -0
  93. package/courses/terraform-infrastructure-setup/scenarios/level-3/advanced-debugging-shift.yaml +63 -0
  94. package/courses/terraform-infrastructure-setup/scenarios/level-3/api-rate-limiting.yaml +50 -0
  95. package/courses/terraform-infrastructure-setup/scenarios/level-3/conditional-resources.yaml +66 -0
  96. package/courses/terraform-infrastructure-setup/scenarios/level-3/drift-detection.yaml +66 -0
  97. package/courses/terraform-infrastructure-setup/scenarios/level-3/dynamic-blocks.yaml +71 -0
  98. package/courses/terraform-infrastructure-setup/scenarios/level-3/large-scale-refactoring.yaml +59 -0
  99. package/courses/terraform-infrastructure-setup/scenarios/level-3/multi-provider-config.yaml +69 -0
  100. package/courses/terraform-infrastructure-setup/scenarios/level-3/state-surgery.yaml +57 -0
  101. package/courses/terraform-infrastructure-setup/scenarios/level-3/terraform-cloud-enterprise.yaml +59 -0
  102. package/courses/terraform-infrastructure-setup/scenarios/level-3/terraform-debugging.yaml +51 -0
  103. package/courses/terraform-infrastructure-setup/scenarios/level-4/blast-radius-management.yaml +51 -0
  104. package/courses/terraform-infrastructure-setup/scenarios/level-4/cicd-pipeline-design.yaml +50 -0
  105. package/courses/terraform-infrastructure-setup/scenarios/level-4/compliance-as-code.yaml +46 -0
  106. package/courses/terraform-infrastructure-setup/scenarios/level-4/cost-estimation-governance.yaml +42 -0
  107. package/courses/terraform-infrastructure-setup/scenarios/level-4/expert-debugging-shift.yaml +51 -0
  108. package/courses/terraform-infrastructure-setup/scenarios/level-4/iac-organization-strategy.yaml +45 -0
  109. package/courses/terraform-infrastructure-setup/scenarios/level-4/incident-response-iac.yaml +47 -0
  110. package/courses/terraform-infrastructure-setup/scenarios/level-4/infrastructure-testing.yaml +41 -0
  111. package/courses/terraform-infrastructure-setup/scenarios/level-4/module-registry-design.yaml +45 -0
  112. package/courses/terraform-infrastructure-setup/scenarios/level-4/multi-account-strategy.yaml +57 -0
  113. package/courses/terraform-infrastructure-setup/scenarios/level-5/board-infrastructure-investment.yaml +53 -0
  114. package/courses/terraform-infrastructure-setup/scenarios/level-5/disaster-recovery-iac.yaml +47 -0
  115. package/courses/terraform-infrastructure-setup/scenarios/level-5/enterprise-iac-transformation.yaml +48 -0
  116. package/courses/terraform-infrastructure-setup/scenarios/level-5/iac-technology-evolution.yaml +49 -0
  117. package/courses/terraform-infrastructure-setup/scenarios/level-5/ma-infrastructure-consolidation.yaml +54 -0
  118. package/courses/terraform-infrastructure-setup/scenarios/level-5/master-debugging-shift.yaml +53 -0
  119. package/courses/terraform-infrastructure-setup/scenarios/level-5/multi-cloud-strategy.yaml +49 -0
  120. package/courses/terraform-infrastructure-setup/scenarios/level-5/platform-engineering.yaml +47 -0
  121. package/courses/terraform-infrastructure-setup/scenarios/level-5/regulatory-compliance-automation.yaml +47 -0
  122. package/courses/terraform-infrastructure-setup/scenarios/level-5/terraform-vs-alternatives.yaml +46 -0
  123. package/dist/cli/commands/generate.d.ts.map +1 -1
  124. package/dist/cli/commands/generate.js +2 -1
  125. package/dist/cli/commands/generate.js.map +1 -1
  126. package/dist/cli/commands/train.d.ts.map +1 -1
  127. package/dist/cli/commands/train.js +6 -3
  128. package/dist/cli/commands/train.js.map +1 -1
  129. package/dist/cli/index.js +9 -6
  130. package/dist/cli/index.js.map +1 -1
  131. package/dist/cli/run-demo.js +3 -2
  132. package/dist/cli/run-demo.js.map +1 -1
  133. package/dist/engine/model-utils.d.ts +6 -0
  134. package/dist/engine/model-utils.d.ts.map +1 -1
  135. package/dist/engine/model-utils.js +28 -1
  136. package/dist/engine/model-utils.js.map +1 -1
  137. package/dist/engine/training.d.ts.map +1 -1
  138. package/dist/engine/training.js +4 -3
  139. package/dist/engine/training.js.map +1 -1
  140. package/dist/generator/course-generator.d.ts.map +1 -1
  141. package/dist/generator/course-generator.js +4 -3
  142. package/dist/generator/course-generator.js.map +1 -1
  143. package/dist/mcp/server.d.ts.map +1 -1
  144. package/dist/mcp/server.js +7 -3
  145. package/dist/mcp/server.js.map +1 -1
  146. package/dist/mcp/session-manager.d.ts.map +1 -1
  147. package/dist/mcp/session-manager.js +3 -2
  148. package/dist/mcp/session-manager.js.map +1 -1
  149. package/package.json +1 -1
@@ -0,0 +1,71 @@
1
+ meta:
2
+ id: plan-output-reading
3
+ level: 1
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Read terraform plan output — interpret change symbols, understand resource actions, identify destructive changes before apply"
7
+ tags: [Terraform, plan, output, changes, destroy, beginner]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Your terraform plan shows this output and you need to understand
13
+ what will happen before approving:
14
+
15
+ ```
16
+ Terraform will perform the following actions:
17
+
18
+ # aws_instance.web will be destroyed and re-created
19
+ # (because ami has changed)
20
+ -/+ resource "aws_instance" "web" {
21
+ ~ ami = "ami-old123" -> "ami-new456" # forces replacement
22
+ ~ arn = "arn:aws:ec2:..." -> (known after apply)
23
+ ~ id = "i-abc123" -> (known after apply)
24
+ instance_type = "t3.micro"
25
+ ~ public_ip = "54.1.2.3" -> (known after apply)
26
+ + secondary_private_ips = (known after apply)
27
+ - tags = {} -> null
28
+ # (15 unchanged attributes hidden)
29
+ }
30
+
31
+ # aws_s3_bucket.data will be updated in-place
32
+ ~ resource "aws_s3_bucket" "data" {
33
+ id = "my-data-bucket"
34
+ ~ tags = {
35
+ + "Environment" = "prod"
36
+ }
37
+ }
38
+
39
+ # aws_security_group.old will be destroyed
40
+ - resource "aws_security_group" "old" {
41
+ - id = "sg-old789" -> null
42
+ - name = "old-sg" -> null
43
+ }
44
+
45
+ # aws_security_group.new will be created
46
+ + resource "aws_security_group" "new" {
47
+ + id = (known after apply)
48
+ + name = "new-sg"
49
+ }
50
+
51
+ Plan: 2 to add, 1 to change, 2 to destroy.
52
+ ```
53
+
54
+ Task: Explain how to read terraform plan output, what each symbol
55
+ means (+, -, ~, -/+), what "forces replacement" means and why it's
56
+ dangerous, "known after apply" values, and best practices for
57
+ reviewing plans before apply.
58
+
59
+ assertions:
60
+ - type: llm_judge
61
+ criteria: "Plan symbols are explained — + (create): new resource will be created. - (destroy): existing resource will be deleted. ~ (update in-place): resource will be modified without recreation. -/+ (destroy and recreate): resource must be destroyed and recreated (replacement). +/- (create before destroy): new resource created first, then old destroyed (lifecycle create_before_destroy). Within attributes: + (added), - (removed), ~ (changed). 'forces replacement' means changing that attribute requires destroying and recreating the resource (e.g., changing AMI on EC2 instance). '(known after apply)' means the value will be determined by the cloud provider during creation"
62
+ weight: 0.35
63
+ description: "Plan symbols"
64
+ - type: llm_judge
65
+ criteria: "Dangerous changes are identified — destroy and recreate (-/+) is dangerous: causes downtime, new IP address, new resource ID. The example: changing AMI forces EC2 instance replacement — means the server goes down, gets a new public IP, loses ephemeral storage. Review all -/+ changes carefully. Mitigation: lifecycle { create_before_destroy = true } creates the new resource before destroying the old one (reduces downtime). Pure destroy (-) is also dangerous: verify you actually want to remove the resource. Summary line 'Plan: 2 to add, 1 to change, 2 to destroy' is the quick check"
66
+ weight: 0.35
67
+ description: "Dangerous changes"
68
+ - type: llm_judge
69
+ criteria: "Plan review best practices are practical — always run plan before apply. Save plan: terraform plan -out=plan.tfplan, then terraform apply plan.tfplan (prevents drift between plan and apply). In CI/CD: plan on PR, apply on merge. Review checklist: (1) any destroys? expected? (2) any replacements? understand why? (3) count of changes matches expectations? (4) no sensitive data exposed in plan output? Use terraform plan -target=resource to plan specific resources. terraform plan -detailed-exitcode: exit 0 (no changes), exit 1 (error), exit 2 (changes present) — useful in scripts"
70
+ weight: 0.30
71
+ description: "Review practices"
@@ -0,0 +1,54 @@
1
+ meta:
2
+ id: resource-creation-failures
3
+ level: 1
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Debug resource creation failures — diagnose API errors, dependency issues, naming conflicts, and partial apply states"
7
+ tags: [Terraform, resources, apply, errors, dependencies, beginner]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ You run `terraform apply` and it partially succeeds:
13
+
14
+ ```
15
+ aws_vpc.main: Creating...
16
+ aws_vpc.main: Creation complete after 3s [id=vpc-0abc123def456]
17
+ aws_subnet.public: Creating...
18
+ aws_subnet.public: Creation complete after 1s [id=subnet-0abc789]
19
+ aws_security_group.web: Creating...
20
+
21
+ Error: creating Security Group (web-sg): InvalidGroup.Duplicate:
22
+ The security group 'web-sg' already exists for VPC 'vpc-0abc123def456'
23
+
24
+ aws_instance.web: Creating...
25
+
26
+ Error: creating EC2 Instance: UnauthorizedOperation: You are not
27
+ authorized to perform this operation. Encoded authorization failure
28
+ message: ...
29
+ ```
30
+
31
+ State after partial apply:
32
+ - VPC: created ✓
33
+ - Subnet: created ✓
34
+ - Security Group: FAILED ✗
35
+ - EC2 Instance: FAILED ✗
36
+
37
+ Task: Explain how terraform apply works (dependency graph, parallel
38
+ creation, partial state), what happens when apply partially fails,
39
+ how to recover from partial failures, common resource creation errors
40
+ (duplicates, permissions, quotas), and terraform plan vs apply workflow.
41
+
42
+ assertions:
43
+ - type: llm_judge
44
+ criteria: "Apply process is explained — terraform builds a dependency graph (DAG) and creates resources in parallel where possible. Resources with dependencies wait for their dependencies. Partial failure: successfully created resources are saved to state. Failed resources are not in state. On next apply, Terraform will try to create the failed resources again (it won't recreate already-created ones). The state file tracks what exists. Recovery: fix the errors and run apply again. terraform plan shows what will happen without making changes"
45
+ weight: 0.35
46
+ description: "Apply process"
47
+ - type: llm_judge
48
+ criteria: "Common creation errors are diagnosed — (1) Duplicate resource: security group already exists outside Terraform. Fix: import it (terraform import) or use a unique name. (2) UnauthorizedOperation: IAM permissions missing. Decode the message: aws sts decode-authorization-message. Fix: add required IAM permissions. (3) Quota exceeded: AWS service limits. Fix: request limit increase. (4) Invalid parameter: wrong AMI for region, invalid CIDR block. (5) Timeout: resource takes too long to create (increase timeouts in resource block)"
49
+ weight: 0.35
50
+ description: "Common errors"
51
+ - type: llm_judge
52
+ criteria: "Plan vs apply workflow is practical — terraform plan: preview changes without modifying infrastructure. Shows: resources to add (+), change (~), destroy (-). Save plan: terraform plan -out=tfplan, then terraform apply tfplan (ensures exactly the planned changes are applied). Always review plan before apply in production. terraform apply -auto-approve: skips confirmation (only for CI/CD, not manual runs). terraform destroy: removes all managed resources. Partial state: use terraform state list to see what's managed, terraform show for current state"
53
+ weight: 0.30
54
+ description: "Plan vs apply"
@@ -0,0 +1,70 @@
1
+ meta:
2
+ id: resource-references
3
+ level: 1
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Fix resource reference errors — debug circular dependencies, missing attributes, implicit vs explicit dependencies, and data source lookups"
7
+ tags: [Terraform, references, dependencies, data-sources, expressions, beginner]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Your Terraform configuration has reference errors:
13
+
14
+ ```
15
+ Error: Cycle: aws_security_group.web, aws_security_group.db
16
+
17
+ Error: Unsupported attribute
18
+
19
+ on main.tf line 25:
20
+ 25: vpc_id = aws_vpc.main.vpc_id
21
+
22
+ A managed resource "aws_vpc" "main" has not been declared in the
23
+ root module.
24
+ ```
25
+
26
+ Your configuration:
27
+
28
+ ```hcl
29
+ resource "aws_security_group" "web" {
30
+ ingress {
31
+ from_port = 443
32
+ to_port = 443
33
+ security_groups = [aws_security_group.db.id]
34
+ }
35
+ }
36
+
37
+ resource "aws_security_group" "db" {
38
+ ingress {
39
+ from_port = 5432
40
+ to_port = 5432
41
+ security_groups = [aws_security_group.web.id]
42
+ }
43
+ }
44
+
45
+ resource "aws_subnet" "public" {
46
+ vpc_id = aws_vpc.main.vpc_id
47
+ }
48
+ ```
49
+
50
+ The VPC already exists in AWS (created by another team) — you need
51
+ to reference it, not create it.
52
+
53
+ Task: Explain Terraform resource references, implicit vs explicit
54
+ dependencies, circular dependency detection and resolution, data
55
+ sources for reading existing infrastructure, and expression syntax
56
+ for accessing resource attributes.
57
+
58
+ assertions:
59
+ - type: llm_judge
60
+ criteria: "Resource references and dependencies are explained — implicit dependency: when resource A references resource B's attribute (aws_security_group.web.id), Terraform automatically creates A after B. Explicit dependency: depends_on = [aws_security_group.web] when there's no attribute reference but order matters. Circular dependency: A references B and B references A — Terraform can't determine creation order. Fix: break the cycle by using aws_security_group_rule as separate resources instead of inline ingress blocks, or use depends_on with one direction only"
61
+ weight: 0.35
62
+ description: "Dependencies"
63
+ - type: llm_judge
64
+ criteria: "Data sources are explained — data sources read existing infrastructure without managing it. data 'aws_vpc' 'main' { filter { name = 'tag:Name', values = ['production'] } } reads the VPC. Reference: data.aws_vpc.main.id. Use data sources when: resource exists outside your Terraform config, managed by another team/state, or pre-existing infrastructure. Common data sources: aws_ami (find latest AMI), aws_vpc, aws_subnet, aws_caller_identity (current AWS account), aws_region. Data sources are refreshed on every plan"
65
+ weight: 0.35
66
+ description: "Data sources"
67
+ - type: llm_judge
68
+ criteria: "Expression syntax is covered — resource attributes: aws_instance.web.id, aws_instance.web.public_ip. With count: aws_instance.web[0].id or aws_instance.web[*].id (splat). With for_each: aws_instance.web['key'].id. Module outputs: module.vpc.vpc_id. Data sources: data.aws_vpc.main.id. Local values: local.common_tags. Built-in functions: lookup(), element(), concat(), join(). Conditional: condition ? true_val : false_val. For expressions: [for s in var.list : upper(s)]"
69
+ weight: 0.30
70
+ description: "Expression syntax"
@@ -0,0 +1,73 @@
1
+ meta:
2
+ id: state-file-basics
3
+ level: 1
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Understand Terraform state — diagnose state file corruption, lock conflicts, state drift, and local vs remote state tradeoffs"
7
+ tags: [Terraform, state, tfstate, locking, drift, beginner]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Your colleague runs `terraform plan` and gets unexpected results:
13
+
14
+ ```
15
+ $ terraform plan
16
+
17
+ Note: Objects have changed outside of Terraform
18
+
19
+ Terraform detected the following changes made outside of Terraform
20
+ since the last "terraform apply":
21
+
22
+ # aws_instance.web has been changed
23
+ ~ resource "aws_instance" "web" {
24
+ ~ instance_type = "t3.micro" -> "t3.large"
25
+ # (10 unchanged attributes hidden)
26
+ }
27
+
28
+ Terraform will perform the following actions:
29
+
30
+ # aws_instance.web will be updated in-place
31
+ ~ resource "aws_instance" "web" {
32
+ ~ instance_type = "t3.large" -> "t3.micro"
33
+ }
34
+
35
+ Plan: 0 to add, 1 to change, 0 to destroy.
36
+ ```
37
+
38
+ Someone changed the instance type in the AWS console from t3.micro
39
+ to t3.large. Terraform wants to revert it back to match the code.
40
+
41
+ Also, when two people run terraform at the same time:
42
+ ```
43
+ Error: Error acquiring the state lock
44
+
45
+ Error message: ConditionalCheckFailedException: The conditional
46
+ request failed
47
+ Lock Info:
48
+ ID: 12345-abcde
49
+ Path: my-bucket/prod/terraform.tfstate
50
+ Operation: OperationTypeApply
51
+ Who: colleague@laptop
52
+ Version: 1.7.0
53
+ Created: 2024-01-15 10:30:00 UTC
54
+ ```
55
+
56
+ Task: Explain Terraform state fundamentals, what the state file
57
+ contains and why it exists, state drift detection and resolution,
58
+ state locking (why it matters, how it works with DynamoDB), and
59
+ local vs remote state.
60
+
61
+ assertions:
62
+ - type: llm_judge
63
+ criteria: "State fundamentals are explained — terraform.tfstate is a JSON file mapping configuration to real infrastructure IDs. It tracks: resource IDs, attribute values, dependencies, metadata. Why state exists: (1) map config to real resources (Terraform needs to know which aws_instance.web is vpc-abc123), (2) track metadata (dependencies), (3) performance (cache attribute values instead of querying APIs every time). State is the source of truth for what Terraform manages. Drift: when real infrastructure differs from state, detected during plan/apply refresh"
64
+ weight: 0.35
65
+ description: "State fundamentals"
66
+ - type: llm_judge
67
+ criteria: "Drift detection and resolution are covered — Terraform refreshes state before plan (compares real infrastructure to state). Drift detected: plan shows changes to revert. Options: (1) apply to revert to code (desired state wins), (2) update code to match reality (if the manual change was intentional), (3) terraform apply -refresh-only to update state without changing infrastructure. Best practice: all changes through Terraform, never manual. If manual changes are needed: update the .tf files to match, then plan to confirm no changes"
68
+ weight: 0.35
69
+ description: "Drift resolution"
70
+ - type: llm_judge
71
+ criteria: "Locking and remote state are practical — local state: terraform.tfstate in working directory. Problem: not shared, no locking, easy to lose. Remote state: store in S3, GCS, Azure Blob, Terraform Cloud. S3 backend with DynamoDB: S3 stores state file, DynamoDB provides locking (prevents concurrent modifications). Lock error: someone else is running terraform. Fix: wait for them to finish, or terraform force-unlock <ID> (dangerous, only if lock is stale). Never commit terraform.tfstate to git (contains secrets). Add to .gitignore"
72
+ weight: 0.30
73
+ description: "Locking and remote"
@@ -0,0 +1,58 @@
1
+ meta:
2
+ id: terraform-fmt-validate
3
+ level: 1
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Use terraform fmt and validate — enforce consistent formatting, catch configuration errors before plan, and set up pre-commit hooks"
7
+ tags: [Terraform, fmt, validate, formatting, pre-commit, beginner]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Your team's Terraform codebase is a formatting mess. Every developer
13
+ uses different indentation, alignment, and spacing. Code reviews are
14
+ full of style nitpicks instead of substance:
15
+
16
+ ```hcl
17
+ resource "aws_instance" "web" {
18
+ ami = "ami-0c55b159cbfafe1f0"
19
+ instance_type="t3.micro"
20
+ tags={
21
+ Name ="web-server"
22
+ Environment= "prod"
23
+ }
24
+ }
25
+
26
+ variable "region" {
27
+ type=string
28
+ default ="us-east-1"
29
+ }
30
+ ```
31
+
32
+ Additionally, a developer pushed this broken config that wasn't caught
33
+ until CI ran terraform plan (wasting 10 minutes):
34
+
35
+ ```hcl
36
+ resource "aws_s3_bucket" "data" {
37
+ bucket = var.bucket_name
38
+ acl = "private" # acl argument removed in AWS provider v4+
39
+ }
40
+ ```
41
+
42
+ Task: Explain terraform fmt (auto-formatting), terraform validate
43
+ (configuration checking), how to enforce both in CI/CD and pre-commit
44
+ hooks, and the difference between validate and plan for error catching.
45
+
46
+ assertions:
47
+ - type: llm_judge
48
+ criteria: "terraform fmt is explained — terraform fmt rewrites .tf files to canonical format (2-space indent, aligned equals signs, consistent spacing). terraform fmt -check: returns non-zero exit code if files need formatting (for CI). terraform fmt -recursive: formats all .tf files in subdirectories. terraform fmt -diff: shows the formatting changes. The example code would be auto-fixed to consistent 2-space indentation with aligned = signs. Best practice: run fmt before every commit"
49
+ weight: 0.35
50
+ description: "Formatting"
51
+ - type: llm_judge
52
+ criteria: "terraform validate is explained with its limitations — validate checks: syntax errors, invalid argument names, type mismatches, missing required arguments, invalid resource references. validate does NOT check: cloud API validity (wrong AMI ID), permissions, resource existence, provider-specific logic. The acl argument error: validate might not catch this because it depends on provider version schema. Plan catches more because it initializes providers and checks against their schemas. Workflow: fmt → validate → plan → apply. validate is fast (no API calls), plan is thorough (makes API calls)"
53
+ weight: 0.35
54
+ description: "Validation"
55
+ - type: llm_judge
56
+ criteria: "CI/CD and pre-commit integration are practical — pre-commit hook: use pre-commit framework with terraform_fmt and terraform_validate hooks. CI pipeline: (1) terraform fmt -check -recursive (fail if unformatted), (2) terraform init -backend=false (for validate only), (3) terraform validate, (4) terraform plan. This catches formatting issues before PR, validation errors without cloud access, and full errors with plan. Tools: pre-commit-terraform hooks, GitHub Actions, GitLab CI. TFLint for additional linting beyond validate (naming conventions, deprecated syntax, best practices)"
57
+ weight: 0.30
58
+ description: "CI integration"
@@ -0,0 +1,58 @@
1
+ meta:
2
+ id: count-vs-for-each
3
+ level: 2
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Choose between count and for_each — understand index-based vs key-based resources, migration pitfalls, and when to use each"
7
+ tags: [Terraform, count, for_each, meta-arguments, iteration, intermediate]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Your infrastructure uses count for EC2 instances:
13
+
14
+ ```hcl
15
+ variable "instances" {
16
+ default = ["web-1", "web-2", "web-3"]
17
+ }
18
+
19
+ resource "aws_instance" "web" {
20
+ count = length(var.instances)
21
+ ami = "ami-0c55b159cbfafe1f0"
22
+ instance_type = "t3.micro"
23
+ tags = {
24
+ Name = var.instances[count.index]
25
+ }
26
+ }
27
+ ```
28
+
29
+ A developer removes "web-2" from the list. Terraform plan shows:
30
+
31
+ ```
32
+ # aws_instance.web[1] will be updated in-place (web-3 → web-2 tags)
33
+ # aws_instance.web[2] will be destroyed
34
+
35
+ Plan: 0 to add, 1 to change, 1 to destroy.
36
+ ```
37
+
38
+ The web-3 instance gets renamed to web-2, and the real web-3 instance
39
+ gets destroyed! This is the wrong behavior — you wanted to remove
40
+ web-2, not web-3.
41
+
42
+ Task: Explain count vs for_each, why count causes index shift problems,
43
+ how for_each solves this with stable keys, how to migrate from count
44
+ to for_each safely, and when to use each approach.
45
+
46
+ assertions:
47
+ - type: llm_judge
48
+ criteria: "Count problems are explained — count uses numeric indices: web[0], web[1], web[2]. Removing a middle element shifts all subsequent indices. Removing 'web-2' (index 1) makes 'web-3' become index 1 — Terraform sees index 1 changed and index 2 disappeared. Result: wrong instance modified, wrong instance destroyed. This is a fundamental limitation of count with lists that can have elements removed. Count is safe only when: (1) all elements are identical, (2) you only add/remove from the end, (3) the count is a simple number not derived from a list"
49
+ weight: 0.35
50
+ description: "Count problems"
51
+ - type: llm_judge
52
+ criteria: "for_each solution is explained — for_each uses stable map keys: web['web-1'], web['web-2'], web['web-3']. Removing 'web-2' only affects web['web-2'] — other instances untouched. Implementation: resource 'aws_instance' 'web' { for_each = toset(var.instances), tags = { Name = each.key } } or with a map: for_each = var.instances_map, using each.key and each.value. for_each accepts: set(string) or map. Not list — use toset() to convert. Access instances: aws_instance.web['web-1'].id"
53
+ weight: 0.35
54
+ description: "for_each solution"
55
+ - type: llm_judge
56
+ criteria: "Migration strategy is covered — migrating count to for_each changes resource addresses (web[0] → web['web-1']). Without state management, Terraform destroys and recreates all instances. Safe migration: (1) use moved blocks (Terraform 1.1+): moved { from = aws_instance.web[0], to = aws_instance.web['web-1'] }. (2) Or use terraform state mv: terraform state mv 'aws_instance.web[0]' 'aws_instance.web[\"web-1\"]'. Verify with plan — should show no changes. When to use count: simple numeric repetition (create N identical resources). When to use for_each: named resources, resources that may be individually added/removed"
57
+ weight: 0.30
58
+ description: "Migration"
@@ -0,0 +1,80 @@
1
+ meta:
2
+ id: dependency-management
3
+ level: 2
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Manage resource dependencies — debug dependency graphs, resolve circular references, use depends_on correctly, and understand the DAG"
7
+ tags: [Terraform, dependencies, DAG, circular, depends-on, intermediate]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Your infrastructure has a complex dependency chain that's causing
13
+ issues during apply:
14
+
15
+ ```hcl
16
+ resource "aws_iam_role" "lambda" {
17
+ name = "lambda-role"
18
+ assume_role_policy = jsonencode({...})
19
+ }
20
+
21
+ resource "aws_iam_role_policy" "lambda" {
22
+ role = aws_iam_role.lambda.name
23
+ policy = jsonencode({
24
+ Statement = [{
25
+ Action = "s3:GetObject"
26
+ Resource = aws_s3_bucket.data.arn
27
+ }]
28
+ })
29
+ }
30
+
31
+ resource "aws_lambda_function" "processor" {
32
+ function_name = "processor"
33
+ role = aws_iam_role.lambda.arn
34
+ handler = "index.handler"
35
+ runtime = "nodejs18.x"
36
+ filename = "lambda.zip"
37
+ }
38
+
39
+ resource "aws_s3_bucket_notification" "trigger" {
40
+ bucket = aws_s3_bucket.data.id
41
+ lambda_function {
42
+ lambda_function_arn = aws_lambda_function.processor.arn
43
+ events = ["s3:ObjectCreated:*"]
44
+ }
45
+ }
46
+
47
+ resource "aws_lambda_permission" "s3" {
48
+ action = "lambda:InvokeFunction"
49
+ function_name = aws_lambda_function.processor.function_name
50
+ principal = "s3.amazonaws.com"
51
+ source_arn = aws_s3_bucket.data.arn
52
+ }
53
+ ```
54
+
55
+ Error:
56
+ ```
57
+ Error: error creating S3 Bucket Notification: Unable to validate
58
+ the following destination configurations: Lambda function ARN
59
+
60
+ The Lambda function doesn't have permission to be invoked by S3 yet
61
+ (the permission resource hasn't been created).
62
+ ```
63
+
64
+ Task: Explain the Terraform dependency graph (DAG), implicit vs
65
+ explicit dependencies, how to debug dependency ordering issues,
66
+ terraform graph command, and depends_on best practices.
67
+
68
+ assertions:
69
+ - type: llm_judge
70
+ criteria: "DAG and implicit dependencies are explained — Terraform builds a directed acyclic graph (DAG) from resource references. Implicit: when resource A uses resource B's attribute, A depends on B. The chain: role → role_policy (references role.name), role → lambda (references role.arn), bucket → notification (references bucket.id), lambda → notification (references lambda.arn). The error: s3_bucket_notification depends on lambda (implicit) but NOT on lambda_permission (no attribute reference). S3 notification tries to verify the Lambda ARN but permission doesn't exist yet"
71
+ weight: 0.35
72
+ description: "DAG explained"
73
+ - type: llm_judge
74
+ criteria: "The fix uses depends_on correctly — add depends_on = [aws_lambda_permission.s3] to the aws_s3_bucket_notification resource. This creates an explicit dependency where no implicit one exists. depends_on is needed because the notification resource doesn't reference any attribute of the permission resource, but the permission must exist for the notification to succeed. terraform graph: visualize dependencies with terraform graph | dot -Tsvg > graph.svg. Look for missing edges that represent real-world dependencies"
75
+ weight: 0.35
76
+ description: "Fix with depends_on"
77
+ - type: llm_judge
78
+ criteria: "depends_on best practices are covered — use depends_on sparingly: prefer implicit dependencies (reference attributes). depends_on forces sequential creation (reduces parallelism). Common scenarios needing depends_on: IAM permissions before resources that need them, DNS records before health checks, network resources before resources placed in them (when ID isn't directly referenced). Anti-pattern: depends_on everywhere 'just in case' — slows down apply. Use terraform graph to verify dependency order before adding depends_on. Module-level depends_on: depends_on on module blocks waits for entire module to complete"
79
+ weight: 0.30
80
+ description: "Best practices"
@@ -0,0 +1,66 @@
1
+ meta:
2
+ id: intermediate-debugging-shift
3
+ level: 2
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Combined intermediate shift — handle module errors, state corruption, and lifecycle issues during a busy infrastructure day"
7
+ tags: [Terraform, troubleshooting, combined, shift-simulation, intermediate]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Three issues hit your team today:
13
+
14
+ Issue 1 — Module version conflict:
15
+ ```
16
+ $ terraform init -upgrade
17
+
18
+ Error: Failed to query available provider packages
19
+
20
+ Module "vpc" (source: terraform-aws-modules/vpc/aws, version 5.5.0)
21
+ requires aws provider >= 5.30.0, but the root module constrains
22
+ aws to ~> 4.0.
23
+ ```
24
+ The VPC module was upgraded but the root module still pins an old
25
+ provider version.
26
+
27
+ Issue 2 — State file corruption:
28
+ ```
29
+ $ terraform plan
30
+
31
+ Error: Failed to load state: unsupported state file format
32
+
33
+ The state file could not be loaded. Terraform detected that the
34
+ state file is not a supported format.
35
+ ```
36
+ Someone manually edited the state file and introduced a JSON syntax
37
+ error.
38
+
39
+ Issue 3 — Unexpected resource replacement:
40
+ ```
41
+ $ terraform plan
42
+
43
+ # aws_db_instance.main must be replaced
44
+ -/+ resource "aws_db_instance" "main" {
45
+ ~ engine_version = "14.9" -> "14.11" # forces replacement
46
+ }
47
+ ```
48
+ Updating the PostgreSQL minor version triggers a full database
49
+ replacement (destroy + create) instead of an in-place upgrade!
50
+
51
+ Task: Diagnose and resolve all three issues with proper explanations
52
+ and preventive measures.
53
+
54
+ assertions:
55
+ - type: llm_judge
56
+ criteria: "Issue 1 (provider version conflict) is resolved — the module requires aws >= 5.30.0 but root constrains to ~> 4.0 (allows 4.x only). Fix options: (1) update root provider constraint to ~> 5.0 (breaking changes between v4 and v5 — review changelog), (2) pin module to an older version compatible with aws ~> 4.0, (3) gradually migrate by testing with aws ~> 5.0 in dev first. Prevention: use version ranges that allow updates (~> 5.0 not = 5.5.0), test module upgrades in non-prod first, terraform init -upgrade in CI to catch conflicts early"
57
+ weight: 0.35
58
+ description: "Version conflict"
59
+ - type: llm_judge
60
+ criteria: "Issue 2 (state corruption) is resolved — state file is JSON, manual edits can break it. Recovery: (1) if using S3 backend with versioning: restore previous version from S3 version history. (2) terraform state pull from backup. (3) If no backup: terraform import all resources again (last resort). Prevention: NEVER manually edit state files — use terraform state mv/rm/import commands. Enable S3 versioning on state bucket. Set up automated state backups. Use DynamoDB locking to prevent concurrent writes"
61
+ weight: 0.35
62
+ description: "State corruption"
63
+ - type: llm_judge
64
+ criteria: "Issue 3 (unexpected replacement) is resolved — some RDS parameter changes force replacement instead of in-place modification. The engine_version change: check AWS provider docs for which attributes force replacement. Fix options: (1) use allow_major_version_upgrade or apply_immediately for in-place upgrades, (2) check if the provider version has a bug (some versions incorrectly force replacement), (3) use lifecycle { ignore_changes = [engine_version] } and manage upgrades outside Terraform. Prevention: always review plan for -/+ changes, test infrastructure changes in dev before prod, pin exact engine versions and upgrade deliberately"
65
+ weight: 0.30
66
+ description: "Unexpected replacement"
@@ -0,0 +1,51 @@
1
+ meta:
2
+ id: lifecycle-rules
3
+ level: 2
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Use lifecycle meta-arguments — configure create_before_destroy, prevent_destroy, ignore_changes, and replace_triggered_by for safe resource management"
7
+ tags: [Terraform, lifecycle, create-before-destroy, prevent-destroy, ignore-changes, intermediate]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Three lifecycle issues in your infrastructure:
13
+
14
+ Issue 1 — Zero-downtime deployment:
15
+ Changing the launch template for an ASG causes recreation. During the
16
+ gap between destroy and create, no instances serve traffic:
17
+ ```
18
+ -/+ aws_launch_template.web (forces replacement)
19
+ ```
20
+
21
+ Issue 2 — Accidental database deletion:
22
+ A developer runs terraform destroy targeting a specific module but
23
+ accidentally includes the RDS instance:
24
+ ```
25
+ aws_db_instance.production: Destroying... [id=prod-db]
26
+ aws_db_instance.production: Destruction complete
27
+ ```
28
+
29
+ Issue 3 — Auto-scaling interference:
30
+ Terraform keeps resetting the ASG desired_capacity back to 2, undoing
31
+ auto-scaling that scaled to 5 during peak traffic:
32
+ ```
33
+ ~ desired_capacity = 5 -> 2
34
+ ```
35
+
36
+ Task: Explain all lifecycle meta-arguments, when to use each,
37
+ common pitfalls, and real-world patterns for safe resource management.
38
+
39
+ assertions:
40
+ - type: llm_judge
41
+ criteria: "create_before_destroy is explained — lifecycle { create_before_destroy = true }: creates the new resource before destroying the old one. Fixes Issue 1: new launch template created first, ASG updated to use it, then old template destroyed. Use for: resources that must have zero downtime (load balancers, launch templates, security groups). Pitfall: some resources have unique constraints (names must be unique) — use name_prefix instead of name to allow both to exist simultaneously. Not all resources support this — some have global uniqueness requirements"
42
+ weight: 0.35
43
+ description: "create_before_destroy"
44
+ - type: llm_judge
45
+ criteria: "prevent_destroy and ignore_changes are explained — prevent_destroy = true: Terraform errors if any operation would destroy the resource. Fixes Issue 2: protects databases, S3 buckets, encryption keys. To actually destroy: remove prevent_destroy first, then destroy. ignore_changes = [desired_capacity]: tells Terraform to ignore changes to specific attributes. Fixes Issue 3: auto-scaling can change desired_capacity without Terraform reverting it. Use ignore_changes for: attributes managed by external systems (auto-scaling, external controllers). ignore_changes = all: ignore all attribute changes (resource only managed for creation)"
46
+ weight: 0.35
47
+ description: "prevent and ignore"
48
+ - type: llm_judge
49
+ criteria: "replace_triggered_by and patterns are covered — replace_triggered_by = [aws_ami.latest.id]: force replacement when a different resource changes. Use for: instances that should be recreated when AMI updates. Lifecycle patterns: databases always get prevent_destroy, ASGs get ignore_changes on desired_capacity, stateless resources get create_before_destroy for zero downtime. Pitfall: ignore_changes can mask drift — use sparingly and document why. Lifecycle rules are meta-arguments, not resource arguments — they go in the lifecycle {} block inside the resource"
50
+ weight: 0.30
51
+ description: "Patterns"
@@ -0,0 +1,58 @@
1
+ meta:
2
+ id: locals-and-expressions
3
+ level: 2
4
+ course: terraform-infrastructure-setup
5
+ type: output
6
+ description: "Use locals and expressions effectively — simplify complex configurations with local values, for expressions, conditionals, and built-in functions"
7
+ tags: [Terraform, locals, expressions, functions, conditionals, intermediate]
8
+
9
+ state: {}
10
+
11
+ trigger: |
12
+ Your Terraform configuration has duplicated logic everywhere:
13
+
14
+ ```hcl
15
+ resource "aws_instance" "web" {
16
+ tags = {
17
+ Name = "web-${var.environment}-${var.region}"
18
+ Environment = var.environment
19
+ Project = var.project
20
+ ManagedBy = "terraform"
21
+ CostCenter = var.environment == "prod" ? "CC-100" : "CC-200"
22
+ }
23
+ }
24
+
25
+ resource "aws_s3_bucket" "data" {
26
+ tags = {
27
+ Name = "data-${var.environment}-${var.region}"
28
+ Environment = var.environment
29
+ Project = var.project
30
+ ManagedBy = "terraform"
31
+ CostCenter = var.environment == "prod" ? "CC-100" : "CC-200"
32
+ }
33
+ }
34
+
35
+ # Same tags repeated on 20 more resources...
36
+ ```
37
+
38
+ You also need to transform a list of subnet CIDRs into a map keyed
39
+ by availability zone, and conditionally create resources based on
40
+ environment.
41
+
42
+ Task: Explain locals (local values), Terraform expressions (for,
43
+ conditionals, splat), built-in functions (lookup, merge, concat,
44
+ flatten, try), and how to use them to simplify configurations.
45
+
46
+ assertions:
47
+ - type: llm_judge
48
+ criteria: "Locals are explained — locals { common_tags = { Environment = var.environment, Project = var.project, ManagedBy = 'terraform', CostCenter = var.environment == 'prod' ? 'CC-100' : 'CC-200' } }. Reference: tags = merge(local.common_tags, { Name = 'web-server' }). Locals compute values once and reuse them. Use for: common tags, computed names, complex expressions used multiple times. Locals vs variables: variables are inputs from outside, locals are computed inside the configuration. Don't overuse locals — if a value is used once, just inline it"
49
+ weight: 0.35
50
+ description: "Locals"
51
+ - type: llm_judge
52
+ criteria: "Expressions are covered — for expression: [for s in var.subnets : s.cidr] (list), {for s in var.subnets : s.az => s.cidr} (map). Conditional: var.create_vpc ? 1 : 0 with count for conditional resource creation. Splat: aws_instance.web[*].id gets all IDs. Ternary: condition ? true_val : false_val. for with filtering: [for s in var.subnets : s.cidr if s.public]. String templates: 'Hello ${var.name}'. Heredoc: <<-EOT for multi-line strings"
53
+ weight: 0.35
54
+ description: "Expressions"
55
+ - type: llm_judge
56
+ criteria: "Built-in functions are practical — merge(): combine maps (merge(local.common_tags, local.extra_tags)). lookup(): safe map access with default (lookup(var.amis, var.region, 'ami-default')). concat(): join lists. flatten(): flatten nested lists. try(): return first non-error value (try(var.config.setting, 'default')). coalesce(): first non-null value. keys()/values(): extract from maps. length(): collection size. format/formatlist(): string formatting. cidrsubnet(): calculate subnet CIDRs. templatefile(): render template files. Type conversion: toset(), tomap(), tolist(), tonumber(), tostring()"
57
+ weight: 0.30
58
+ description: "Functions"