Skip to content

Validation Contract — Single Source of Truth

Audience: Contributors | Status: Stable — Internal | Verified against: v0.43.0

Covers issues #23, #24, and #357.

This document defines the canonical validation rule contract for CloudBlocks. All frontend and backend validation must derive from this specification. No layer may invent rules that are not listed here.


1. Ownership and Authority

Aspect Policy
Rule owner This document (docs/design/VALIDATION_CONTRACT.md)
Change process PR with updates to this doc + corresponding FE/BE code changes in the same PR
Versioning Semantic — bump this document's Current version when adding/removing/changing rules
Current version 1.1.0

2. Rule Schema

Every validation rule is identified by a unique ruleId and produces a ValidationError:

interface ValidationError {
  ruleId: string; // Unique rule identifier (e.g., "rule-db-private")
  severity: 'error' | 'warning';
  message: string; // Human-readable description
  suggestion: string; // Actionable fix suggestion
  targetId: string; // ID of the entity that violates the rule
}

3. Placement Rules (Legacy Category-based)

Placement rules validate that blocks are placed on appropriate container blocks.

Rule ID Severity Condition Message
rule-container-block-exists error Block has no placementId or container block not found Block is not placed on any container block
rule-compute-subnet error Compute block not on a subnet container block Compute block must be placed on a Subnet container block
rule-db-private error Database block not on a subnet container block with subnetAccess: "private" Database block must be placed on a private Subnet container block
rule-gw-public error Gateway block not on a subnet container block with subnetAccess: "public" Gateway block must be placed on a public Subnet container block
rule-storage-subnet error Storage block not on a subnet container block Storage block must be placed on a Subnet container block
rule-analytics-subnet error Analytics block not on a subnet container block Analytics block must be placed on a Subnet container block
rule-identity-subnet error Identity block not on a subnet container block Identity block must be placed on a Subnet container block
rule-observability-subnet error Observability block not on a subnet container block Observability block must be placed on a Subnet container block
rule-serverless-network error function, queue, or event block not on a region container block Serverless blocks (function/queue/event) must be placed on a Region container block

3.1 v2.0 Layer Hierarchy Rules

These rules are defined for the next-generation layer system but are not yet wired into the main engine.ts orchestrator.

Rule ID Severity Condition Message
rule-layer-hierarchy error Block placed on a container block that is not a valid parent layer Invalid layer hierarchy for this block type
rule-grid-alignment error Block position not CU-aligned (integer coordinates) Block must be aligned to the grid
rule-no-overlap error Block overlaps with sibling on same container block (AABB detection) Block cannot overlap with other blocks

4. Connection Rules

Connection rules validate dataflow between blocks. Connections follow initiator semantics — the source is the client/initiator, the target is the server/receiver.

Rule ID Severity Condition Message
rule-conn-source error Source endpoint ID not found in blocks or external actors Connection source not found
rule-conn-target error Target endpoint ID not found in blocks or external actors Connection target not found
rule-conn-self error sourceId === targetId A block cannot connect to itself
rule-conn-invalid error Source → Target pair not in allowed connections map Invalid connection: {source} → {target}

Allowed Connection Map

Source (Initiator) Allowed Targets (Receiver)
internet gateway
gateway compute, function
compute database, storage, analytics, identity, observability
function storage, database, queue
queue function
event function

database, storage, analytics, identity, and observability are receiver-only. queue and event can only connect to function.

Implementation References

  • Frontend: apps/web/src/entities/validation/connection.ts
  • Backend: Not yet implemented (planned for Milestone 6 server-side validation)

5. Aggregation Rules

Validation for block aggregation (scaling/clustering) configuration.

Rule ID Severity Condition Message
rule-aggregation-count error block.aggregation.count < 1 or count is not an integer Aggregation count must be a positive integer

Implementation References

  • Frontend: apps/web/src/entities/validation/aggregation.ts
  • Backend: Not yet implemented (planned for Milestone 6)

5.1 Application Placement Rules (Planned — Not Yet Implemented)

Status: Planned. The Application entity and its placement rules are designed but have no corresponding implementation. The rules below describe the intended behavior for a future milestone.

Rule ID Severity Condition Message
rule-aggregation-count error Aggregation count < 1 or non-integer Block has invalid aggregation count (must be >= 1 integer)

Aggregation Behavior

  • If a block has no aggregation field, it is treated as a single instance (valid).
  • Aggregation count must be a positive integer (≥ 1).
  • Block size remains fixed regardless of count — aggregation is visual only (badge "×N").

Implementation References (Application)

  • Frontend: apps/web/src/entities/validation/aggregation.ts
  • Backend: Not yet implemented (planned for Milestone 6)

6. Role Rules

Validation for identity and access management roles.

Rule ID Severity Condition Message
rule-role-invalid error Role not in BLOCK_ROLES list Invalid role assigned to block
rule-role-duplicate warning Same role appears more than once on a block Duplicate role assigned

7. Provider Validation Rules (Warnings)

Specific rules based on cloud provider characteristics.

Rule ID Severity Condition Message
rule-provider-aws-lambda-subnet warning AWS Lambda placed on a subnet (may not need VPC) AWS Lambda may not require a subnet placement unless VPC access is needed
rule-provider-gcp-sql-public warning GCP Cloud SQL on a public subnet GCP Cloud SQL is usually restricted to private access
rule-provider-unknown-subtype warning Block subtype not in known provider subtypes Unknown resource subtype for this provider

Known Subtypes Table

Provider validation uses the internal KNOWN_SUBTYPES map to verify resource alignment.


8. Orchestration

The validation engine iterates all blocks and connections, collecting errors and warnings into a single ValidationResult through 5 distinct passes:

  1. Placement Pass (placement.ts)
  2. Aggregation Pass (aggregation.ts)
  3. Role Pass (role.ts)
  4. Connection Pass (connection.ts)
  5. Provider Pass (providerValidation.ts)
interface ValidationResult {
  valid: boolean; // true when errors.length === 0
  errors: ValidationError[];
  warnings: ValidationError[];
}

Implementation References

  • Frontend:
  • Orchestrator: apps/web/src/entities/validation/engine.ts
  • Rules: placement.ts, connection.ts, aggregation.ts, role.ts, providerValidation.ts
  • v2.0 layer rules: defined in placement.ts (not yet wired into engine.ts)
  • Backend: Not yet implemented (planned for Milestone 6 server-side validation)

9. FE/BE Alignment Contract

Current State (Milestone 5)

  • Frontend: Full validation engine implemented in TypeScript (entities/validation/)
  • Backend: No server-side validation. The backend is a thin orchestration layer that trusts frontend-validated data.

Future State (Milestone 6+)

When backend validation is introduced:

  1. Rule definitions must be generated from this document — no hand-written rule divergence.
  2. Compatibility tests must exist: a shared JSON test fixture file (tests/fixtures/validation-cases.json) containing input architectures and expected validation results. Both FE and BE test suites must consume this file.
  3. Rule additions: Add to this document first, then implement in both layers in the same PR.
  4. Rule changes: Update this document, update both implementations, update shared fixtures.

Compatibility Test Format

{
  "contractVersion": "1.1.0",
  "cases": [
    {
      "name": "database-on-public-subnet",
      "input": { "blocks": [...], "containerBlocks": [...], "connections": [...] },
      "expected": {
        "valid": false,
        "errors": [{ "ruleId": "rule-db-private", "targetId": "block-db01" }]
      }
    }
  ]
}

10. Migration Notes

  • Serverless block categories (FunctionBlock, QueueBlock, EventBlock) are implemented and reflected in the placement rules above.
  • When adding new connection types (e.g., EventFlow), update the allowed connection map here first.
  • Breaking rule changes (removing a rule, changing severity) require a version bump to this document's Current version field.