Files
AGENTS/skills/excalidraw/references/validation.md
m3tm3re 63cd7fe102 Rename directories to plural form: skill/ → skills/, agent/ → agents/, command/ → commands/
- Rename skill/ to skills/ for consistency with naming conventions
- Rename agent/ to agents/ and command/ to commands/
- Update AGENTS.md with all directory references
- Update scripts/test-skill.sh paths
- Update prompts/athena.txt documentation

This aligns with best practices of using plural directory names and updates
all documentation to reflect the new structure.
2026-01-26 20:42:05 +01:00

5.2 KiB

Validation Reference

Checklists, validation algorithms, and common bug fixes.


Pre-Flight Validation Algorithm

Run BEFORE writing the file:

FUNCTION validateDiagram(elements):
  errors = []

  // 1. Validate shape-text bindings
  FOR each shape IN elements WHERE shape.boundElements != null:
    FOR each binding IN shape.boundElements:
      textElement = findById(elements, binding.id)
      IF textElement == null:
        errors.append("Shape {shape.id} references missing text {binding.id}")
      ELSE IF textElement.containerId != shape.id:
        errors.append("Text containerId doesn't match shape")

  // 2. Validate arrow connections
  FOR each arrow IN elements WHERE arrow.type == "arrow":
    sourceShape = findShapeNear(elements, arrow.x, arrow.y)
    IF sourceShape == null:
      errors.append("Arrow {arrow.id} doesn't start from shape edge")

    finalPoint = arrow.points[arrow.points.length - 1]
    endX = arrow.x + finalPoint[0]
    endY = arrow.y + finalPoint[1]
    targetShape = findShapeNear(elements, endX, endY)
    IF targetShape == null:
      errors.append("Arrow {arrow.id} doesn't end at shape edge")

    IF arrow.points.length > 2:
      IF arrow.elbowed != true:
        errors.append("Arrow {arrow.id} missing elbowed:true")
      IF arrow.roundness != null:
        errors.append("Arrow {arrow.id} should have roundness:null")

  // 3. Validate unique IDs
  ids = [el.id for el in elements]
  duplicates = findDuplicates(ids)
  IF duplicates.length > 0:
    errors.append("Duplicate IDs: {duplicates}")

  // 4. Validate bounding boxes
  FOR each arrow IN elements WHERE arrow.type == "arrow":
    maxX = max(abs(p[0]) for p in arrow.points)
    maxY = max(abs(p[1]) for p in arrow.points)
    IF arrow.width < maxX OR arrow.height < maxY:
      errors.append("Arrow {arrow.id} bounding box too small")

  RETURN errors

FUNCTION findShapeNear(elements, x, y, tolerance=15):
  FOR each shape IN elements WHERE shape.type IN ["rectangle", "ellipse"]:
    edges = [
      (shape.x + shape.width/2, shape.y),              // top
      (shape.x + shape.width/2, shape.y + shape.height), // bottom
      (shape.x, shape.y + shape.height/2),             // left
      (shape.x + shape.width, shape.y + shape.height/2)  // right
    ]
    FOR each edge IN edges:
      IF abs(edge.x - x) < tolerance AND abs(edge.y - y) < tolerance:
        RETURN shape
  RETURN null

Checklists

Before Generating

  • Identified all components from codebase
  • Mapped all connections/data flows
  • Chose layout pattern (vertical, horizontal, hub-and-spoke)
  • Selected color palette (default, AWS, Azure, K8s)
  • Planned grid positions
  • Created ID naming scheme

During Generation

  • Every labeled shape has BOTH shape AND text elements
  • Shape has boundElements: [{ "type": "text", "id": "{id}-text" }]
  • Text has containerId: "{shape-id}"
  • Multi-point arrows have elbowed: true, roundness: null, roughness: 0
  • Arrows have startBinding and endBinding
  • No diamond shapes used
  • Applied staggering formula for multiple arrows

Arrow Validation (Every Arrow)

  • Arrow x,y calculated from shape edge
  • Final point offset = targetEdge - sourceEdge
  • Arrow width = max(abs(point[0]))
  • Arrow height = max(abs(point[1]))
  • U-turn arrows have 40-60px clearance

After Generation

  • All boundElements IDs reference valid text elements
  • All containerId values reference valid shapes
  • All arrows start within 15px of shape edge
  • All arrows end within 15px of shape edge
  • No duplicate IDs
  • Arrow bounding boxes match points
  • File is valid JSON

Common Bugs and Fixes

Bug: Arrow appears disconnected/floating

Cause: Arrow x,y not calculated from shape edge.

Fix:

Rectangle bottom: arrow_x = shape.x + shape.width/2
                  arrow_y = shape.y + shape.height

Bug: Arrow endpoint doesn't reach target

Cause: Final point offset calculated incorrectly.

Fix:

target_edge = (target.x + target.width/2, target.y)
offset_x = target_edge.x - arrow.x
offset_y = target_edge.y - arrow.y
Final point = [offset_x, offset_y]

Bug: Multiple arrows from same source overlap

Cause: All arrows start from identical x,y.

Fix: Stagger start positions:

For 5 arrows from bottom edge:
  arrow1.x = shape.x + shape.width * 0.2
  arrow2.x = shape.x + shape.width * 0.35
  arrow3.x = shape.x + shape.width * 0.5
  arrow4.x = shape.x + shape.width * 0.65
  arrow5.x = shape.x + shape.width * 0.8

Bug: Callback arrow doesn't loop correctly

Cause: U-turn path lacks clearance.

Fix: Use 4-point path:

Points = [[0, 0], [clearance, 0], [clearance, -vert], [final_x, -vert]]
clearance = 40-60px

Bug: Labels don't appear inside shapes

Cause: Using label property instead of separate text element.

Fix: Create TWO elements:

  1. Shape with boundElements referencing text
  2. Text with containerId referencing shape

Bug: Arrows are curved, not 90-degree

Cause: Missing elbow properties.

Fix: Add all three:

{
  "roughness": 0,
  "roundness": null,
  "elbowed": true
}