Skip to main content

State Machines

Five state machines wired together via EventBridge. ASL JSON definitions in this directory; CDK reads them at synth time. Per-SM diagrams in ./diagrams/.

Pipeline

GuardDuty NO_THREATS_FOUND (native EventBridge)

move-clean-document.asl.json copy upload → clean bucket, delete original
↓ S3 Object Created on clean-documents bucket
classification.asl.json Textract Lending → type + confidence + page breakdown
↓ DocumentProcessing-Classified (EventBridge rule filters on classification + numeric matchers)
extraction.asl.json Bedrock Data Automation, custom blueprint, splitter enabled
↓ DocumentProcessing-Extracted
context-gathering.asl.json applicant profile from DynamoDB
↓ DocumentProcessing-ContextGathered
claude-analysis.asl.json Bedrock managed prompt + forced tool use, persist to DDB
↓ DocumentProcessing-Completed

State machines

2. classification.asl.json

📊 Diagram

Textract Lending Analysis. Reports the dominant document type + numeric confidence. EventBridge routes downstream based on type and the numeric thresholds in config/routing-policy.json.

  • Polling strategy: uses getLendingAnalysisSummary (small response, returns JobStatus + Summary) for both polling and final fetch. Deliberately does not call getLendingAnalysis — that endpoint returns the full Documents[] extraction payload which can exceed Step Functions' 256 KB state limit on multi-page docs.
  • JSONata ExtractClassification: filters UNCLASSIFIED as noise, picks dominant from classified pages only, confidence = dominantTypePages / classifiedPages. Comparator is boolean ($a.pageCount < $b.pageCount), not numeric — JSONata's $sort quirk.
  • S3 tag preservation: reads existing tags and appends the Classification tag, preserving ApplicationNumber, LicenceNumber, etc.
  • Emits: DocumentProcessing-Classified with { classification, classificationConfidence, totalPages, classifiedPages, dominantTypePages, pageBreakdown, documentSizeBytes, textractJobId }. One event regardless of doc type — routing is per-rule at the bus.
  • Failure mode: INVALID_IMAGE_TYPE (HEIC, WebP, DOCX) or other Textract job failure → routes to caseworker-review path (currently emits a typed failure event the test harness picks up).
  • Timeout: 15 minutes.

Common ASL patterns

Retry with exponential backoff

{
"Retry": [
{
"ErrorEquals": ["ThrottlingException"],
"IntervalSeconds": 2,
"MaxAttempts": 3,
"BackoffRate": 2
}
]
}

Catch + route to failure

{
"Catch": [
{
"ErrorEquals": ["States.ALL"],
"ResultPath": "$.error",
"Next": "EmitFailureEvent"
}
]
}

Emit a typed event

{
"Type": "Task",
"Resource": "arn:aws:states:::events:putEvents",
"Parameters": {
"Entries": [
{
"Detail": { "bucket.$": "$.bucket", "key.$": "$.key" },
"DetailType": "DocumentProcessing-Completed",
"Source": "custom.documentProcessing"
}
]
}
}

JSONata (Pass state)

Used in classification.asl.json for the dominant-type calculation. Note JSONata's $sort takes a boolean comparator (true means $a should come after $b), not numeric like JavaScript.

$sort($breakdown, function($a, $b){ $a.pageCount < $b.pageCount })

Modifying a step

# Edit ASL JSON
vi state-machines/classification.asl.json

CDK reads ASL files at synth time and embeds them in the state machine resources. No code change needed for ASL edits.

Validating

Online: ASL Validator or the AWS Step Functions Workflow Studio.

CLI:

aws stepfunctions validate-state-machine-definition \
--definition file://classification.asl.json

References