STATEDIAGRAM.md
May 30, 2026 Β· View on GitHub
π EU Parliament Monitor β State Diagrams
π System State Transitions and Lifecycle Management
π― Behavioral Model for Static News Generation Platform
π Document Owner: CEO | π Version: 1.5 | π
Last Updated:
2026-05-30 (UTC) | π·οΈ Platform Release: v0.9.26
π Review Cycle: Quarterly | β° Next Review: 2026-08-30
π·οΈ Classification: Public (Open Source European Parliament Monitoring
Platform)
π Architecture Documentation Map
| Document | Focus | Description | Documentation Link |
|---|---|---|---|
| Architecture | ποΈ Architecture | C4 model showing current system structure | View Source |
| Future Architecture | ποΈ Architecture | C4 model showing future system structure | View Source |
| Mindmaps | π§ Concept | Current system component relationships | View Source |
| Future Mindmaps | π§ Concept | Future capability evolution | View Source |
| SWOT Analysis | πΌ Business | Current strategic assessment | View Source |
| Future SWOT Analysis | πΌ Business | Future strategic opportunities | View Source |
| Data Model | π Data | Current data structures and relationships | View Source |
| Future Data Model | π Data | Enhanced European Parliament data architecture | View Source |
| Flowcharts | π Process | Current data processing workflows | View Source |
| Future Flowcharts | π Process | Enhanced AI-driven workflows | View Source |
| State Diagrams | π Behavior | Current system state transitions | View Source |
| Future State Diagrams | π Behavior | Enhanced adaptive state transitions | View Source |
| Security Architecture | π‘οΈ Security | Current security implementation | View Source |
| Future Security Architecture | π‘οΈ Security | Security enhancement roadmap | View Source |
| Threat Model | π― Security | STRIDE threat analysis | View Source |
| Classification | π·οΈ Governance | CIA classification & BCP | View Source |
| CRA Assessment | π‘οΈ Compliance | Cyber Resilience Act | View Source |
| Workflows | βοΈ DevOps | CI/CD documentation | View Source |
| Future Workflows | π DevOps | Planned CI/CD enhancements | View Source |
| Business Continuity Plan | π Resilience | Recovery planning | View Source |
| Financial Security Plan | π° Financial | Cost & security analysis | View Source |
| End-of-Life Strategy | π¦ Lifecycle | Technology EOL planning | View Source |
| Unit Test Plan | π§ͺ Testing | Unit testing strategy | View Source |
| E2E Test Plan | π Testing | End-to-end testing | View Source |
| Performance Testing | β‘ Performance | Performance benchmarks | View Source |
| Security Policy | π Security | Vulnerability reporting & security policy | View Source |
π‘οΈ ISMS Policy Alignment
This state diagram documentation implements controls aligned with Hack23 AB's publicly available ISMS framework.
Applicable ISMS Policies
| Policy | Relevance |
|---|---|
| Secure Development Policy | State management follows secure SDLC lifecycle |
| Information Security Policy | System state transitions comply with security governance |
| Incident Response Plan | Error and failure states trigger incident response procedures |
| Change Management Policy | Deployment state transitions follow change management process |
π Overview
This document defines all state transitions and lifecycles in the EU Parliament Monitor system. State diagrams capture behavioral aspects that complement the structural views (C4 model), data views (ERD), and process flows (flowcharts).
Purpose
State diagrams serve to:
- Define Valid State Transitions: Document legal state changes and their triggers
- Lifecycle Management: Show complete entity lifecycles from creation to archival
- Error Handling: Illustrate error states and recovery paths
- Concurrency Control: Define states that prevent race conditions
- Audit Trail: Enable state-based audit logging and compliance
System Context
EU Parliament Monitor is a static site generator with:
- Zero Runtime State: No databases, no sessions, no server-side state
- Build-Time State Machine: All state transitions during GitHub Actions execution
- Immutable Outputs: Generated artifacts never modified post-creation
- Idempotent Operations: Repeated executions produce consistent results
- Graceful Degradation: Fallback states when external dependencies unavailable
π― System Lifecycle State
The overall system operates in phases from initialization through publication and monitoring.
stateDiagram-v2
[*] --> Idle: System Ready
Idle --> Initializing: Workflow Triggered<br/>(Schedule/Manual)
Initializing --> ConfigurationLoading: Load Configuration
ConfigurationLoading --> EnvironmentValidation: Validate Environment
EnvironmentValidation --> DependencyCheck: Check Dependencies
DependencyCheck --> DependencyInstall: Missing Dependencies
DependencyInstall --> DependencyCheck: Retry
DependencyCheck --> InitializationFailed: Max Retries Exceeded
DependencyCheck --> Ready: All Dependencies OK
Ready --> MCPConnection: Connect to Data Sources
state MCPConnection {
[*] --> ConnectingMCP
ConnectingMCP --> MCPConnected: Connection Successful
ConnectingMCP --> MCPRetrying: Connection Failed
MCPRetrying --> ConnectingMCP: Backoff Wait
MCPRetrying --> MCPFallback: Max Retries
MCPConnected --> [*]
MCPFallback --> [*]
}
MCPConnection --> DataFetching: Data Source Ready
DataFetching --> Generating: Data Retrieved
DataFetching --> GeneratingFallback: MCP Unavailable
Generating --> Validating: Articles Generated
GeneratingFallback --> Validating: Placeholder Content
Validating --> Testing: Validation Passed
Validating --> ValidationFailed: Validation Failed
ValidationFailed --> Generating: Fix & Retry
Testing --> TestFailed: Tests Failed
Testing --> Publishing: Tests Passed
TestFailed --> [*]: Abort Workflow
Publishing --> Deployed: Git Push Success
Publishing --> PublishFailed: Git Push Failed
PublishFailed --> Publishing: Retry
PublishFailed --> [*]: Max Retries
Deployed --> Monitoring: GitHub Pages Deploy
Monitoring --> Idle: Complete
InitializationFailed --> [*]: Fatal Error
note right of Idle
Waiting for next scheduled
execution (06:00 UTC) or
manual workflow_dispatch
end note
note right of MCPConnection
European Parliament MCP Server
connection with retry logic
and graceful fallback
end note
note right of Deployed
Static files committed to
main branch, GitHub Pages
automatically deploys
end note
System State Definitions
| State | Description | Entry Conditions | Exit Conditions | Timeout |
|---|---|---|---|---|
| Idle | System waiting for trigger | Previous workflow complete OR system startup | Schedule reached OR manual dispatch | N/A |
| Initializing | Loading configuration and environment | Workflow triggered | Config loaded successfully | 30s |
| ConfigurationLoading | Reading package.json, .env files | Initialization started | Config parsed and validated | 10s |
| EnvironmentValidation | Checking environment variables, Node version | Config loaded | Environment meets requirements | 10s |
| DependencyCheck | Verifying npm packages installed | Environment validated | All deps available OR missing deps identified | 15s |
| DependencyInstall | Running npm ci to install packages | Missing dependencies detected | Installation complete | 180s |
| InitializationFailed | Fatal error during startup | Repeated failures, missing critical config | Workflow terminates | N/A |
| Ready | System prepared to execute generation | All checks passed | Data source connection initiated | 5s |
| MCPConnection | Connecting to European Parliament MCP Server | Ready state achieved | Connected OR fallback mode | 30s |
| DataFetching | Retrieving parliamentary data via MCP | MCP connected | Data retrieved OR fallback | 60s |
| Generating | Creating multi-language articles | Data available | All articles generated | 300s |
| GeneratingFallback | Creating placeholder articles | MCP unavailable | Placeholder articles generated | 60s |
| Validating | Running HTML validation, schema checks | Generation complete | Validation passed OR failed | 45s |
| ValidationFailed | Detected invalid output | Validation checks failed | Retry generation OR abort | 10s |
| Testing | Executing ESLint, tests, security scans | Validation passed | Tests passed OR failed | 120s |
| TestFailed | Test suite failures detected | Test execution failed | Workflow aborted | 10s |
| Publishing | Committing and pushing to Git | Tests passed | Git push successful OR failed | 30s |
| PublishFailed | Git push failed | Git operation failed | Retry OR abort | 10s |
| Deployed | Changes pushed to GitHub | Git push successful | GitHub Pages deployment initiated | 5s |
| Monitoring | Awaiting GitHub Pages deployment | Deployed | Deployment complete | 180s |
State Transition Rules
Legal Transitions:
- Forward progression through pipeline stages
- Retry loops for transient failures (MCP connection, Git push)
- Fallback paths for graceful degradation (MCP β Fallback content)
- Error exits to Idle state with notification
Illegal Transitions (prevented by workflow):
- Cannot skip validation after generation
- Cannot publish without passing tests
- Cannot retry indefinitely (max 3 retries for connections)
- Cannot modify deployed content (immutable artifacts)
π° Article Lifecycle State
Individual news articles progress through generation, validation, publication, and archival states.
stateDiagram-v2
[*] --> ArticlePending: Article Scheduled
ArticlePending --> DataCollecting: Fetch Source Data
state DataCollecting {
[*] --> FetchingPlenary
FetchingPlenary --> FetchingCommittee: Plenary Data OK
FetchingCommittee --> FetchingDocuments: Committee Data OK
FetchingDocuments --> FetchingQuestions: Document Data OK
FetchingQuestions --> DataComplete: Question Data OK
FetchingPlenary --> DataFetchError: API Error
FetchingCommittee --> DataFetchError: API Error
FetchingDocuments --> DataFetchError: API Error
FetchingQuestions --> DataFetchError: API Error
DataFetchError --> FetchingPlenary: Retry
DataFetchError --> DataFallback: Max Retries
DataComplete --> [*]
DataFallback --> [*]
}
DataCollecting --> ContentGeneration: Data Available
state ContentGeneration {
[*] --> TemplateLoading
TemplateLoading --> LLMPrompting: Template Ready
LLMPrompting --> ContentReceived: LLM Response OK
LLMPrompting --> LLMRetry: LLM Error
LLMRetry --> LLMPrompting: Backoff
LLMRetry --> PlaceholderContent: Max Retries
ContentReceived --> [*]
PlaceholderContent --> [*]
}
ContentGeneration --> ArticleDraft: Content Generated
ArticleDraft --> LanguageProcessing: Process All Languages
state LanguageProcessing {
[*] --> ProcessingEN
ProcessingEN --> ProcessingSV: English OK
ProcessingSV --> ProcessingDA: Swedish OK
ProcessingDA --> ProcessingNO: Danish OK
ProcessingNO --> ProcessingFI: Norwegian OK
ProcessingFI --> ProcessingDE: Finnish OK
ProcessingDE --> ProcessingFR: German OK
ProcessingFR --> ProcessingES: French OK
ProcessingES --> ProcessingNL: Spanish OK
ProcessingNL --> ProcessingAR: Dutch OK
ProcessingAR --> ProcessingHE: Arabic OK
ProcessingHE --> ProcessingJA: Hebrew OK
ProcessingJA --> ProcessingKO: Japanese OK
ProcessingKO --> ProcessingZH: Korean OK
ProcessingZH --> AllLanguagesComplete: Chinese OK
ProcessingEN --> LanguageError: Translation Failed
ProcessingDE --> LanguageError: Translation Failed
ProcessingFR --> LanguageError: Translation Failed
LanguageError --> ProcessingEN: Retry Language
LanguageError --> PartialLanguageSet: Skip Language
AllLanguagesComplete --> [*]
PartialLanguageSet --> [*]
}
LanguageProcessing --> ArticleValidation: All Languages Processed
state ArticleValidation {
[*] --> HTMLValidation
HTMLValidation --> SchemaValidation: HTML Valid
SchemaValidation --> ContentValidation: Schema Valid
ContentValidation --> SecurityValidation: Content Valid
SecurityValidation --> ValidationComplete: Security OK
HTMLValidation --> ValidationFailed: Invalid HTML
SchemaValidation --> ValidationFailed: Invalid Schema
ContentValidation --> ValidationFailed: Invalid Content
SecurityValidation --> ValidationFailed: Security Issue
ValidationComplete --> [*]
ValidationFailed --> [*]
}
ArticleValidation --> ArticleValidated: Validation Passed
ArticleValidation --> ArticleRejected: Validation Failed
ArticleRejected --> ArticleDraft: Fix Issues
ArticleRejected --> ArticleAbandoned: Unfixable
ArticleValidated --> ArticleStaging: Ready for Publish
ArticleStaging --> ArticlePublished: Git Commit Success
ArticlePublished --> ArticleIndexed: Add to Index
ArticleIndexed --> ArticleLive: GitHub Pages Deploy
ArticleLive --> ArticleMonitored: Active Monitoring
ArticleMonitored --> ArticleArchived: 90 Days Old
ArticleArchived --> [*]: Lifecycle Complete
ArticleAbandoned --> [*]: Generation Failed
note right of ArticlePending
14 article types:
Short-form (8):
- Breaking News (every 4h)
- Week Ahead / Week in Review
- Month Ahead / Month in Review
- Committee Reports
- Motions / Propositions
Long-horizon prospective (2):
- Quarter Ahead (T+90d)
- Year Ahead (T+365d)
Long-horizon retrospective (2):
- Quarter in Review
- Year in Review
Electoral overlay (2):
- Term Outlook (today β next-election)
- Election Cycle (Β±6 mo around election)
Each driven by a unified
news-<type>.md gh-aw workflow
(Stages AβE in one session,
deterministic HTML rendered
from Stage-B artifacts by
src/aggregator/article-generator.ts).
Horizon registry:
src/config/article-horizons.ts
(single source of truth for
data window, cadence, mandatory
artifacts, stage budgets,
electoral overlay).
end note
note right of ContentGeneration
LLM generates article with:
- Title & subtitle
- Summary paragraph
- Detailed analysis
- Key points
- Citations
end note
note right of LanguageProcessing
14 languages:
EN, SV, DA, NO, FI, DE,
FR, ES, NL, AR, HE, JA,
KO, ZH
end note
note right of ArticleLive
Immutable content:
Never modified after
publication
end note
Article State Definitions
| State | Description | Duration | Rollback Possible |
|---|---|---|---|
| ArticlePending | Article scheduled for generation | 0-60s | Yes |
| DataCollecting | Fetching source data from EP APIs | 10-60s | Yes |
| ContentGeneration | LLM creating article content | 15-120s | Yes |
| ArticleDraft | Initial content created | 0-5s | Yes |
| LanguageProcessing | Translating to all languages | 30-300s | Yes |
| ArticleValidation | Running validation checks | 10-30s | Yes |
| ArticleRejected | Failed validation | Until fixed | Yes |
| ArticleAbandoned | Permanently failed | Permanent | No |
| ArticleValidated | Passed all checks | 0-5s | Yes |
| ArticleStaging | Ready for commit | 0-10s | Yes |
| ArticlePublished | Committed to Git | Permanent | No* |
| ArticleIndexed | Added to language indexes | Permanent | No |
| ArticleLive | Deployed on GitHub Pages | Until archived | No |
| ArticleMonitored | Active monitoring | 90 days | No |
| ArticleArchived | Moved to archive | Permanent | No |
*Git history allows reverting, but articles are conceptually immutable.
Horizon-family branching (long-horizon expansion 2026-Q2)
Stage-A DataCollecting and Stage-B ContentGeneration follow a different artifact path depending on the horizon family resolved from src/config/article-horizons.ts:
stateDiagram-v2
[*] --> ResolveHorizon: News workflow dispatched
ResolveHorizon --> StandardShortForm: breaking Β· week-* Β· month-* Β· committee-reports Β· motions Β· propositions
ResolveHorizon --> LongHorizonProspective: quarter-ahead Β· year-ahead
ResolveHorizon --> LongHorizonRetrospective: quarter-in-review Β· year-in-review
ResolveHorizon --> ElectoralOverlay: term-outlook Β· election-cycle
state StandardShortForm {
[*] --> ShortForm_StageA: 5 min budget
ShortForm_StageA --> ShortForm_StageB: 22 min budget
ShortForm_StageB --> ShortForm_StageC: 4 min Β· exit minute 36
ShortForm_StageC --> ShortForm_StageD: 2 min budget
ShortForm_StageD --> ShortForm_PR: 2 min Β· PR β€ minute 45
}
state LongHorizonProspective {
[*] --> LHP_StageA: 5 min budget
LHP_StageA --> LHP_StageB: 24-25 min budget Β· forward-projection Β· legislative-pipeline-forecast Β· parliamentary-calendar-projection
LHP_StageB --> LHP_StageC: 4 min Β· exit minute 38-39
LHP_StageC --> LHP_StageD: 2 min budget
LHP_StageD --> LHP_PR: 2 min Β· PR β€ minute 45
}
state LongHorizonRetrospective {
[*] --> LHR_StageA: 4-5 min budget
LHR_StageA --> LHR_StageB: 24-25 min budget Β· cross-run-diff Β· cross-session-intelligence Β· pipeline-forecast
LHR_StageB --> LHR_StageC: 4 min Β· exit minute 38-39
LHR_StageC --> LHR_StageD: 2 min budget
LHR_StageD --> LHR_PR: 2 min Β· PR β€ minute 45
}
state ElectoralOverlay {
[*] --> EO_StageA: 5 min budget
EO_StageA --> EO_StageB: 26-28 min budget Β· electoral artifact set mandatory<br/>term-arc Β· seat-projection Β· mandate-fulfilment-scorecard<br/>presidency-trio-context Β· commission-wp-alignment Β· forward-indicators<br/>+ EP-election scenario branch in scenario-forecast
EO_StageB --> EO_StageC: 4 min Β· exit minute 42 Β· electoral invariants asserted
EO_StageC --> EO_StageD: 2 min budget
EO_StageD --> EO_PR: 2 min Β· PR β€ minute 47
}
ShortForm_PR --> [*]: ArticlePublished
LHP_PR --> [*]: ArticlePublished
LHR_PR --> [*]: ArticlePublished
EO_PR --> [*]: ArticlePublished
note right of ResolveHorizon
Horizon registry returns:
- dataWindow (forward/backward/span)
- cadence + auxiliary triggers
- mandatoryArtifacts list
- stageBudgets {A,B,C,D,E}
- electoralOverlay flag
end note
note right of ElectoralOverlay
Stage-C completeness gate
asserts these invariants when
electoralOverlay = true:
1. mandate-fulfilment-scorecard
is present
2. seat-projection is present
3. scenario-forecast contains
an EP-election outcome branch
4. forwardStatementsHorizonDays
is bounded at β€ 1825
end note
The drift-guard test test/unit/horizon-registry.test.js asserts every horizon's stageBudgets sum is β€ 50 to leave the 10-min buffer for sandbox setup, MCP gateway boot and the safe-output create_pull_request round-trip within the 60-min timeout-minutes cap.
π MCP Connection State Machine
The Model Context Protocol (MCP) connection manages connectivity to the European Parliament data server.
stateDiagram-v2
[*] --> Disconnected: System Start
Disconnected --> Connecting: Initialize Connection
Connecting --> Authenticating: TCP/Stdio Connected
Connecting --> ConnectionTimeout: Timeout (10s)
Authenticating --> Connected: Auth Success
Authenticating --> AuthFailed: Auth Failed
ConnectionTimeout --> RetryWait: Transient Error
AuthFailed --> RetryWait: Retry Auth
RetryWait --> RetryCount: Backoff Complete
state RetryCount <<choice>>
RetryCount --> Connecting: Retry < 3
RetryCount --> FallbackMode: Retry >= 3
Connected --> Healthy: Health Check OK
Healthy --> Active: Ready for Requests
Active --> RequestSending: Tool Call
state RequestSending {
[*] --> SerializingRequest
SerializingRequest --> SendingData: JSON Ready
SendingData --> AwaitingResponse: Data Sent
AwaitingResponse --> ReceivingData: Response Started
ReceivingData --> DeserializingResponse: Data Complete
DeserializingResponse --> RequestComplete: Parse OK
AwaitingResponse --> RequestTimeout: Timeout (30s)
DeserializingResponse --> RequestError: Parse Error
RequestComplete --> [*]
RequestTimeout --> [*]
RequestError --> [*]
}
RequestSending --> Active: Request Success
RequestSending --> RequestFailed: Request Failed
RequestFailed --> RetryRequest: Transient Error
RetryRequest --> RequestSending: Retry
RequestFailed --> Degraded: Persistent Errors
Active --> Degraded: Health Check Failed
Degraded --> Reconnecting: Attempt Recovery
Reconnecting --> Connected: Reconnect Success
Reconnecting --> Disconnected: Reconnect Failed
Connected --> Disconnected: Connection Lost
Disconnected --> FallbackMode: Max Failures
FallbackMode --> [*]: Use Placeholder Content
note right of Disconnected
MCP server not available:
- Server not running
- Network unreachable
- Configuration error
end note
note right of Connected
MCP protocol handshake
complete, server ready
for tool requests
end note
note right of Active
Connection pooling:
- Reuse connection
- Keep-alive pings
- Request queueing
end note
note right of FallbackMode
Graceful degradation:
Generate articles with
placeholder content
end note
MCP Connection States
| State | Description | Timeout | Recovery Action |
|---|---|---|---|
| Disconnected | No active connection | N/A | Initialize connection |
| Connecting | TCP/stdio connection in progress | 10s | Retry with backoff |
| Authenticating | MCP handshake and auth | 5s | Retry auth |
| ConnectionTimeout | Connection attempt exceeded timeout | N/A | Enter retry wait |
| AuthFailed | Authentication rejected | N/A | Check credentials, retry |
| RetryWait | Exponential backoff delay | 1s, 2s, 4s | Retry connecting |
| Connected | MCP handshake complete | N/A | Proceed to health check |
| Healthy | Server health verified | N/A | Transition to active |
| Active | Ready for tool requests | N/A | Process requests |
| RequestSending | Tool call in progress | 30s | Retry on timeout |
| RequestFailed | Request failed | N/A | Retry or degrade |
| Degraded | Persistent errors detected | N/A | Attempt reconnection |
| Reconnecting | Attempting to restore connection | 10s | Reconnect or disconnect |
| FallbackMode | Using placeholder content | N/A | Continue with fallback |
Connection State Rules
Retry Policy:
- Max 3 connection attempts with exponential backoff (1s, 2s, 4s)
- Request retries: 2 attempts for transient errors
- Health checks every 60s when active
- Automatic reconnection on connection loss
Fallback Triggers:
- Max connection retries exhausted
- Persistent authentication failures
- Server consistently unhealthy
- Critical tool call failures
β Validation State Flow
Data and content validation occurs at multiple stages with different validation rules.
stateDiagram-v2
[*] --> ValidationQueued: Data/Content Ready
ValidationQueued --> SchemaValidation: Start Validation
state SchemaValidation {
[*] --> CheckStructure
CheckStructure --> CheckTypes: Structure OK
CheckTypes --> CheckRequired: Types OK
CheckRequired --> CheckConstraints: Required OK
CheckConstraints --> SchemaValid: Constraints OK
CheckStructure --> SchemaInvalid: Missing Fields
CheckTypes --> SchemaInvalid: Type Mismatch
CheckRequired --> SchemaInvalid: Required Missing
CheckConstraints --> SchemaInvalid: Constraint Violation
SchemaValid --> [*]
SchemaInvalid --> [*]
}
SchemaValidation --> ContentValidation: Schema Valid
SchemaValidation --> ValidationFailed: Schema Invalid
state ContentValidation {
[*] --> SanitizeHTML
SanitizeHTML --> RemoveScripts: Strip Dangerous Tags
RemoveScripts --> RemoveEvents: Remove <script> tags
RemoveEvents --> EncodeEntities: Remove onX handlers
EncodeEntities --> ValidateLinks: Encode < > & " '
ValidateLinks --> CheckLength: Verify URLs
CheckLength --> ContentValid: Length OK
CheckLength --> ContentInvalid: Too Long/Short
ValidateLinks --> ContentInvalid: Broken Links
ContentValid --> [*]
ContentInvalid --> [*]
}
ContentValidation --> SecurityValidation: Content Valid
ContentValidation --> ValidationFailed: Content Invalid
state SecurityValidation {
[*] --> XSSCheck
XSSCheck --> SQLInjectionCheck: No XSS
SQLInjectionCheck --> CSRFCheck: No SQLi
CSRFCheck --> ClickjackCheck: No CSRF
ClickjackCheck --> SecurityValid: No Clickjack
XSSCheck --> SecurityInvalid: XSS Detected
SQLInjectionCheck --> SecurityInvalid: SQLi Detected
CSRFCheck --> SecurityInvalid: CSRF Risk
ClickjackCheck --> SecurityInvalid: Clickjack Risk
SecurityValid --> [*]
SecurityInvalid --> [*]
}
SecurityValidation --> HTMLValidation: Security Valid
SecurityValidation --> ValidationFailed: Security Invalid
state HTMLValidation {
[*] --> ParseHTML
ParseHTML --> CheckDoctype: Parse OK
CheckDoctype --> CheckMeta: Doctype OK
CheckMeta --> CheckSemantic: Meta OK
CheckSemantic --> CheckAccessibility: Semantic OK
CheckAccessibility --> HTMLValid: Accessibility OK
ParseHTML --> HTMLInvalid: Parse Error
CheckDoctype --> HTMLInvalid: Missing/Wrong
CheckMeta --> HTMLInvalid: Meta Issues
CheckSemantic --> HTMLInvalid: Semantic Issues
CheckAccessibility --> HTMLInvalid: A11y Issues
HTMLValid --> [*]
HTMLInvalid --> [*]
}
HTMLValidation --> ValidationComplete: HTML Valid
HTMLValidation --> ValidationFailed: HTML Invalid
ValidationComplete --> [*]: All Checks Passed
ValidationFailed --> ErrorLogging: Log Failure Details
ErrorLogging --> RetryDecision: Assess Error
state RetryDecision <<choice>>
RetryDecision --> RetryGeneration: Fixable Error
RetryDecision --> RejectContent: Unfixable Error
RetryGeneration --> ValidationQueued: Retry
RejectContent --> [*]: Validation Failed
note right of SchemaValidation
JSON Schema validation:
- Structure conformance
- Type checking
- Required fields
- Value constraints
end note
note right of ContentValidation
Content sanitization:
- XSS prevention
- HTML injection
- Link validation
- Length limits
end note
note right of SecurityValidation
Security scanning:
- OWASP Top 10
- Input validation
- Output encoding
- CSP compliance
end note
Validation Stage Details
| Validation Type | Checks Performed | Failure Action | Retry Allowed |
|---|---|---|---|
| Schema Validation | JSON structure, types, required fields, constraints | Log error, reject data | Yes (1 retry) |
| Content Validation | HTML sanitization, link validation, length checks | Log error, sanitize or reject | Yes (auto-fix) |
| Security Validation | XSS, SQLi, CSRF, clickjacking, CSP violations | Log error, reject content | No |
| HTML Validation | Parse errors, doctype, meta tags, semantics, accessibility | Log error, auto-fix or reject | Yes (auto-fix) |
π¨ Error State Handling
The system handles errors through structured error states with recovery paths.
stateDiagram-v2
[*] --> OperationNormal: Normal Operation
OperationNormal --> ErrorDetected: Exception/Failure
ErrorDetected --> ErrorClassification: Classify Error
state ErrorClassification <<choice>>
ErrorClassification --> TransientError: Retryable
ErrorClassification --> PersistentError: Non-Retryable
ErrorClassification --> FatalError: Critical
state TransientError {
[*] --> NetworkError
[*] --> TimeoutError
[*] --> RateLimitError
[*] --> ServiceUnavailable
NetworkError --> RetryQueue: Log & Queue
TimeoutError --> RetryQueue: Log & Queue
RateLimitError --> BackoffQueue: Log & Wait
ServiceUnavailable --> RetryQueue: Log & Queue
RetryQueue --> [*]
BackoffQueue --> [*]
}
TransientError --> RetryAttempt: Enter Retry
state RetryAttempt {
[*] --> WaitBackoff
WaitBackoff --> IncrementCounter: Backoff Complete
IncrementCounter --> CheckRetryLimit: Counter++
state CheckRetryLimit <<choice>>
CheckRetryLimit --> RetryOperation: Retry < Max
CheckRetryLimit --> ExhaustedRetries: Retry >= Max
RetryOperation --> [*]: Retry
ExhaustedRetries --> [*]: Give Up
}
RetryAttempt --> OperationNormal: Retry Success
RetryAttempt --> PersistentError: Max Retries
state PersistentError {
[*] --> ValidationError
[*] --> ConfigurationError
[*] --> DataQualityError
[*] --> AuthenticationError
ValidationError --> ErrorLogged: Log Details
ConfigurationError --> ErrorLogged: Log Details
DataQualityError --> ErrorLogged: Log Details
AuthenticationError --> ErrorLogged: Log Details
ErrorLogged --> [*]
}
PersistentError --> FallbackMode: Use Fallback
state FallbackMode {
[*] --> UsePlaceholder
UsePlaceholder --> ContinueWorkflow: Placeholder Active
ContinueWorkflow --> [*]
}
FallbackMode --> OperationDegraded: Continue with Limitations
state FatalError {
[*] --> SystemError
[*] --> SecurityViolation
[*] --> DataCorruption
[*] --> ResourceExhaustion
SystemError --> CriticalAlert: Alert Team
SecurityViolation --> CriticalAlert: Alert Team
DataCorruption --> CriticalAlert: Alert Team
ResourceExhaustion --> CriticalAlert: Alert Team
CriticalAlert --> [*]
}
FatalError --> WorkflowAborted: Terminate
WorkflowAborted --> NotificationSent: Send Alerts
NotificationSent --> [*]: End Workflow
OperationDegraded --> OperationNormal: Recovery
note right of TransientError
Retry with exponential backoff:
- 1st retry: 1s delay
- 2nd retry: 2s delay
- 3rd retry: 4s delay
Max 3 retries
end note
note right of PersistentError
Errors requiring intervention:
- Invalid configuration
- Bad input data
- Authentication issues
- Resource not found
end note
note right of FatalError
Critical failures:
- Security violations
- Data corruption
- Out of memory
- Infinite loops
end note
Error Classification Matrix
| Error Type | Severity | Retry Strategy | Fallback | Alert |
|---|---|---|---|---|
| Network Error | Transient | 3 retries, exponential backoff | Continue with cache | No |
| Timeout Error | Transient | 3 retries, extended timeout | Skip operation | No |
| Rate Limit Error | Transient | Wait + retry (per X-RateLimit headers) | Queue for later | No |
| Service Unavailable | Transient | 3 retries, exponential backoff | Use fallback service | Warning |
| Validation Error | Persistent | 1 retry with fix | Use last valid data | Warning |
| Configuration Error | Persistent | No retry | Use defaults | Error |
| Data Quality Error | Persistent | No retry | Skip corrupt data | Warning |
| Authentication Error | Persistent | 1 retry | Abort workflow | Error |
| System Error | Fatal | No retry | Abort | Critical |
| Security Violation | Fatal | No retry | Abort | Critical |
| Data Corruption | Fatal | No retry | Abort | Critical |
| Resource Exhaustion | Fatal | No retry | Abort | Critical |
π¦ Deployment State Lifecycle
After content generation, the deployment process manages Git operations and GitHub Pages deployment.
stateDiagram-v2
[*] --> PreDeployment: Content Validated
PreDeployment --> GitStaging: Stage Changes
state GitStaging {
[*] --> GitAdd
GitAdd --> GitStatus: Add Files
GitStatus --> ChangesStaged: Verify
ChangesStaged --> [*]
GitAdd --> GitError: Add Failed
GitStatus --> GitError: Status Check Failed
GitError --> [*]
}
GitStaging --> GitCommit: Files Staged
GitStaging --> DeploymentFailed: Staging Failed
state GitCommit {
[*] --> CreateCommit
CreateCommit --> SignCommit: Commit Created
SignCommit --> VerifyCommit: Signature Added
VerifyCommit --> CommitComplete: Verify OK
CreateCommit --> CommitError: Commit Failed
SignCommit --> CommitError: Sign Failed
VerifyCommit --> CommitError: Verify Failed
CommitComplete --> [*]
CommitError --> [*]
}
GitCommit --> GitPush: Commit Success
GitCommit --> DeploymentFailed: Commit Failed
state GitPush {
[*] --> PushToRemote
PushToRemote --> VerifyPush: Push Initiated
VerifyPush --> PushSuccess: Remote Updated
PushToRemote --> PushConflict: Conflict Detected
PushConflict --> PullRebase: Pull Changes
PullRebase --> PushToRemote: Retry Push
PushToRemote --> PushError: Network Error
PushError --> RetryPush: Retry
RetryPush --> PushToRemote: Wait & Retry
PushSuccess --> [*]
PushError --> [*]
}
GitPush --> GitHubPagesQueue: Push Success
GitPush --> DeploymentFailed: Push Failed
state GitHubPagesQueue {
[*] --> Queued
Queued --> Building: Build Started
Building --> Deploying: Build Success
Deploying --> DeploySuccess: Deploy Complete
Building --> BuildError: Build Failed
Deploying --> DeployError: Deploy Failed
BuildError --> [*]
DeployError --> [*]
DeploySuccess --> [*]
}
GitHubPagesQueue --> DeploymentComplete: Pages Live
GitHubPagesQueue --> DeploymentFailed: Pages Failed
DeploymentComplete --> VerifyDeployment: Verify
state VerifyDeployment {
[*] --> HealthCheck
HealthCheck --> ValidateContent: HTTP 200
ValidateContent --> CheckIndexes: Content OK
CheckIndexes --> VerifySuccess: Indexes OK
HealthCheck --> VerifyFailed: HTTP Error
ValidateContent --> VerifyFailed: Content Mismatch
CheckIndexes --> VerifyFailed: Missing Indexes
VerifySuccess --> [*]
VerifyFailed --> [*]
}
VerifyDeployment --> DeploymentMonitored: Verify Success
VerifyDeployment --> DeploymentDegraded: Verify Failed
DeploymentMonitored --> [*]: Deployment Complete
DeploymentFailed --> ErrorNotification: Alert Team
DeploymentDegraded --> WarningNotification: Alert Team
ErrorNotification --> [*]: Workflow Failed
WarningNotification --> DeploymentMonitored: Continue Monitoring
note right of GitCommit
Commit includes:
- Generated articles
- Updated indexes
- Sitemap.xml
Co-authored-by trailer
end note
note right of GitHubPagesQueue
GitHub Pages automatically:
- Builds Jekyll site
- Deploys to CDN
- Updates DNS
~90-180 seconds
end note
note right of VerifyDeployment
Post-deployment checks:
- HTTP status codes
- Content integrity
- Index availability
- Sitemap accessibility
end note
Deployment State Details
| State | Description | Duration | Rollback |
|---|---|---|---|
| PreDeployment | Final checks before commit | 5s | Yes |
| GitStaging | Adding files to Git index | 10s | Yes |
| GitCommit | Creating signed commit | 5s | Yes |
| GitPush | Pushing to GitHub remote | 10-30s | No* |
| GitHubPagesQueue | GitHub Pages build queue | 30-90s | No |
| Building | Jekyll build process | 30-60s | No |
| Deploying | CDN deployment | 30-60s | No |
| DeploymentComplete | Live on GitHub Pages | Permanent | No |
| VerifyDeployment | Post-deploy validation | 30s | N/A |
| DeploymentMonitored | Monitoring active | Ongoing | N/A |
| DeploymentFailed | Critical failure | N/A | Rollback |
| DeploymentDegraded | Partial failure | Until fixed | Manual |
*Git push can be reverted with git revert, but GitHub Pages redeploys.
π Aggregator State Machine
The deterministic aggregator in src/aggregator/ is the canonical post-April-2026 execution spine invoked by every unified news-<type>.md agentic workflow at Stage D. Each module has explicit entry/exit states.
stateDiagram-v2
[*] --> FetchStage: Strategy.run() invoked
state FetchStage {
[*] --> FetchingEP
FetchingEP --> FetchingWB: EP OK
FetchingEP --> FetchingEPRetry: Unavailable envelope
FetchingEPRetry --> FetchingEP: Backoff (mcp-retry.ts)
FetchingEPRetry --> FetchingWB: Max retries (degrade)
FetchingWB --> FetchingIMF: WB OK or OR-gate allows
FetchingWB --> FetchingIMF: WB Skip (optional)
FetchingIMF --> FetchComplete: IMF OK
FetchingIMF --> FetchComplete: IMF skip (WB satisfies OR-gate)
FetchingIMF --> FetchFailed: Both WB+IMF failed
FetchComplete --> [*]
FetchFailed --> [*]
}
FetchStage --> TransformStage: Fetch complete
FetchStage --> PipelineAborted: Fetch failed (economic OR-gate blocked)
state TransformStage {
[*] --> NormalizingEP
NormalizingEP --> NormalizingEconomic: EP normalized
NormalizingEconomic --> Unifying: Economic normalized
Unifying --> TransformComplete: Schema unified
TransformComplete --> [*]
}
TransformStage --> AnalysisStage: Unified data ready
state AnalysisStage {
[*] --> Pass1Writing
Pass1Writing --> Pass1Complete: Pass 1 done (60% budget)
Pass1Complete --> Pass2Improving: Read-back + improve
Pass2Improving --> Pass2Complete: Pass 2 done (40% budget)
Pass2Complete --> IntelligenceFiles: Emit analysis files
IntelligenceFiles --> AnalysisComplete: stakeholder-map.md<br/>impact-matrix.md<br/>mcp-reliability-audit.md<br/>reference-analysis-quality.md
AnalysisComplete --> [*]
Pass1Writing --> AnalysisFailed: Time budget exhausted
AnalysisFailed --> [*]
}
AnalysisStage --> GenerateStage: Analysis complete
AnalysisStage --> PipelineAborted: Analysis failed
state GenerateStage {
[*] --> StrategyBuilder
StrategyBuilder --> StakeholderSlots: buildDefaultStakeholderPerspectives
StakeholderSlots --> ChartEmbedding: AI_MARKER sentinels
ChartEmbedding --> RenderHTML: Chart.js embedded
RenderHTML --> GenerateComplete: HTML rendered
GenerateComplete --> [*]
}
GenerateStage --> OutputStage: HTML ready
state OutputStage {
[*] --> WritingFiles
WritingFiles --> UpdatingIndexes: news/ updated
UpdatingIndexes --> OutputComplete: Indexes + sitemap
OutputComplete --> [*]
}
OutputStage --> ValidatorGate: Ready for gate
ValidatorGate --> [*]: Pass β PR created
ValidatorGate --> PipelineAborted: Fail
PipelineAborted --> [*]: Abort workflow
note right of FetchStage
EP MCP 1.2.13 uniform
unavailable envelope:
{ status:"unavailable",
items:[] }
WB-or-IMF OR-gate via
articlePolicyHasEconomicContext
end note
note right of AnalysisStage
AI-First quality gates:
β₯80 words/SWOT item
β₯150 words/stakeholder
β₯60% prose ratio
β₯1 Chart.js
0 AI_ANALYSIS_REQUIRED
60-min β₯45m; 120-min β₯90m
end note
β Validator-Gate State Machine
node scripts/utils/validate-analysis-completeness.js --article-html=... runs as a pre-translation and pre-PR gate. Implemented via scanHtmlForFallbackLeaks + FALLBACK_TEMPLATE_PATTERNS.
stateDiagram-v2
[*] --> Scanning: Invoked with --article-html
Scanning --> AnalysisPresent: Analysis files exist
Scanning --> MissingManifest: Missing analysis files
AnalysisPresent --> ManifestValid: Reference thresholds met
AnalysisPresent --> InsufficientReferences: Below threshold
ManifestValid --> ArticleClean: No fallback template patterns
ManifestValid --> FallbackLeak: AI_ANALYSIS_REQUIRED or AI_MARKER leak
ArticleClean --> EconomicContextOK: articlePolicyHasEconomicContext passes
ArticleClean --> MissingEconomicContext: No WB and no IMF
EconomicContextOK --> Pass: All gates OK
Pass --> [*]: PR creation allowed
MissingManifest --> Fail
InsufficientReferences --> Fail
FallbackLeak --> Fail
MissingEconomicContext --> Fail
Fail --> [*]: Abort PR
note right of ManifestValid
intelligence/mcp-reliability-audit.md
β₯200 words (breaking β₯385)
intelligence/reference-analysis-quality.md
β₯140 words (breaking β₯190)
Configured in
analysis/methodologies/
reference-quality-thresholds.json
end note
note right of ArticleClean
scanHtmlForFallbackLeaks
checks rendered HTML against
FALLBACK_TEMPLATE_PATTERNS
end note
Validator Failure Categories
| Category | Trigger | Remediation |
|---|---|---|
| MissingManifest | Analysis stage did not emit required intelligence files | Re-run analysis stage with longer time budget |
| InsufficientReferences | Word-count thresholds not met | Extend AI reasoning; verify Pass-2 improvement actually ran |
| FallbackLeak | AI_ANALYSIS_REQUIRED / AI_MARKER sentinels present in rendered HTML | Agent author must fill slots directly; re-run generate stage |
| MissingEconomicContext | Both WB and IMF unavailable | Wait for one economic source to recover, or relax default gate to articlePolicyHasEconomicContext |
π Translation State Machine (news-translate)
The news-translate agentic workflow fans out one EN source article to 13 non-EN languages. A pre-gate scan validates analysis completeness before fan-out to prevent replicating broken EN content across languages.
stateDiagram-v2
[*] --> PreGate: news-translate triggered
state PreGate {
[*] --> ScanAllEnglishSources
ScanAllEnglishSources --> PreGatePass: All pass validator
ScanAllEnglishSources --> PreGateFail: Any EN source fails
PreGatePass --> [*]
PreGateFail --> [*]
}
PreGate --> Fanout: Pre-gate pass
PreGate --> [*]: Pre-gate fail (abort)
state Fanout {
[*] --> Queued13
Queued13 --> InProgress: Per-language job starts
InProgress --> Validated: axe-core + htmlhint pass
Validated --> Committed: Language HTML committed
Committed --> Reconciled: news-translate-reconciler cleanup
Reconciled --> [*]
InProgress --> LanguageFailed: Translation / validation failed
LanguageFailed --> Requeue: Within max-patch-size 10240 KB
Requeue --> InProgress: Retry
LanguageFailed --> SkipLanguage: Max retries
SkipLanguage --> [*]: Partial fan-out
}
Fanout --> PRCreated: All languages processed
PRCreated --> [*]: safe-outputs create-pull-request
note right of PreGate
validate-analysis-completeness.js
runs against every EN HTML
source before fan-out β
prevents fan-out of broken
analysis across 13 languages
end note
note right of Fanout
Languages: sv, da, no, fi, de,
fr, es, nl, ar, he, ja, ko, zh
max-patch-size: 10240 KB
(vs default 1024 KB)
end note
π¦ Unified Workflow Run State Machine (news-<type>.md)
Every unified .github/workflows/news-<type>.md workflow runs Stages A β E in a single 60-minute session and produces exactly one PR. The 14 article-generating workflows (breaking, week-ahead, week-in-review, month-ahead, month-in-review, quarter-ahead, quarter-in-review, year-ahead, year-in-review, term-outlook, election-cycle, committee-reports, motions, propositions) all share this state machine. news-translate.md is the single exception β see Β§Translation State Machine below.
stateDiagram-v2
[*] --> Triggered: cron OR workflow_dispatch
Triggered --> MCPSetup: scripts/mcp-setup.sh
MCPSetup --> StageA: EP_MCP_GATEWAY_URL ready
state StageA {
[*] --> AcquiringEPData
AcquiringEPData --> AcquiringIMF: EP MCP probe
AcquiringIMF --> AcquiringWB: IMF probe (cache/imf/imf-probe-summary.json)
AcquiringWB --> StageAComplete: dataMode resolved (full | degraded-* | title-only | minimal)
StageAComplete --> [*]
}
StageA --> StageB: minute β€ 12 (per-slug budget)
state StageB {
[*] --> AnalysisPass1
AnalysisPass1 --> AnalysisPass2: ~60% of stage budget
AnalysisPass2 --> ArtifactsEmitted: ~40% of stage budget (read-back & extend)
ArtifactsEmitted --> [*]
}
StageB --> StageC: artifacts written under analysis/daily/<date>/<slug>/
state StageC {
[*] --> RunningValidator
RunningValidator --> GREEN: all gates pass
RunningValidator --> GREEN_WITH_WARNINGS: WARN issues only
RunningValidator --> RED: any RED issue (tradecraft, mermaid, requiredSections)
RunningValidator --> ANALYSIS_ONLY: skipArticle flag set
}
StageC --> StageD: GREEN | GREEN_WITH_WARNINGS
StageC --> [*]: RED β STAGE_C_GATE:RED stdout, abort
StageC --> [*]: ANALYSIS_ONLY β no article, manifest updated
state StageD {
[*] --> ArticlePass1
ArticlePass1 --> ArticlePass2: prose draft complete
ArticlePass2 --> HTMLRendered: deterministic aggregator render (src/aggregator/markdown/)
HTMLRendered --> [*]
}
StageD --> StageE: rendered HTML + analysis artifacts ready
state StageE {
[*] --> SafeOutputCall
SafeOutputCall --> PRCreated: safeoutputs___create_pull_request (called exactly once)
PRCreated --> [*]
}
StageE --> Complete: minute β€ 45 (target β€ 42 standard slugs, β€ 47 electoral)
Complete --> [*]: PR awaits review
note right of StageA
Per-slug stage budgets are
authoritative in
src/config/article-horizons.ts
Hard PR deadline minute β€ 45
end note
note right of StageC
Verdict union:
GREEN | GREEN_WITH_WARNINGS |
ANALYSIS_ONLY | PENDING (manifest)
RED is stdout-only β never
persisted to manifest history
end note
Stage Definitions
| Stage | Description | Output | Gate |
|---|---|---|---|
| A | Data acquisition (EP MCP + IMF + World Bank) | Cached envelopes, manifest with dataMode | All sources probed, dataMode resolved |
| B | Analysis (2-pass) β produces 39+ artifacts under analysis/daily/ | Methodology-driven artifact set with WEP/Admiralty grading | Pass 2 read-back complete |
| C | Completeness gate (scripts/validate-analysis-completeness.js) | STAGE_C_GATE:GREEN/RED stdout + manifest.history[].gateResult | RED blocks PR; GREEN allows Stage D |
| D | Article generation (2-pass + deterministic aggregator render) | One HTML article in EN under news/<slug>/<date>/article.html | Aggregator render succeeds |
| E | Single PR creation via safeoutputs___create_pull_request | PR with analysis artifacts + article HTML, exactly one call | Hard deadline minute β€ 45 |
π Manifest dataMode State Machine
Each Stage-A run resolves a manifest dataMode describing data availability for the run. The DataMode union ('full' | 'title-only' | 'degraded-imf' | 'degraded-voting' | 'minimal') is defined in src/workflows/types.ts with line-floor reduction factors in DATA_MODE_REDUCTION. Stage-C uses these factors to scale per-artifact line floors; structural checks (Mermaid, WEP, Admiralty, SATβ₯10) are never reduced.
stateDiagram-v2
[*] --> Probing: Stage A starts
Probing --> Full: EP MCP OK + IMF OK + World Bank OK<br/>(reduction = 1.00)
Probing --> DegradedIMF: EP OK + IMF FAIL/missing + WB OK<br/>(reduction = 0.85)
Probing --> DegradedVoting: EP partial (votes endpoint degraded)<br/>(reduction = 0.85)
Probing --> TitleOnly: EP returns titles only β no body content<br/>(reduction = 0.75)
Probing --> Minimal: Multiple sources unavailable<br/>(reduction = 0.65)
Full --> DegradedIMF: IMF probe expires mid-run
Full --> DegradedVoting: Vote tool times out
DegradedIMF --> Minimal: WB also fails
DegradedVoting --> Minimal: IMF also fails
TitleOnly --> Minimal: Even title fetch degrades
DegradedIMF --> Full: WB satisfies economic OR-gate (no transition needed; reported)
DegradedVoting --> Full: get_latest_votes recovers via DOCEO XML
Full --> [*]: Stage B proceeds at full thresholds
DegradedIMF --> [*]: Stage B with -15% line floors
DegradedVoting --> [*]: Stage B with -15% line floors
TitleOnly --> [*]: Stage B with -25% line floors
Minimal --> [*]: Stage B with -35% line floors
note right of Probing
Stage A determines mode from:
- EP MCP get_server_health
- IMF probe summary
(cache/imf/imf-probe-summary.json)
- World Bank Open Data MCP
end note
note right of Minimal
Minimal mode still requires:
- All structural checks
- WEP banding present
- Admiralty grading present
- β₯10 SATs in
methodology-reflection.md
end note
dataMode Transition Triggers
| From β To | Trigger | Validator behaviour |
|---|---|---|
full β degraded-imf | cache/imf/imf-probe-summary.json reports failure or is missing | -15% line floor; IMF citation requirement falls back to WB |
full β degraded-voting | Vote tool (get_voting_records / get_latest_votes) times out | -15% line floor; voting-pattern artifacts use cached sample |
full β title-only | EP MCP returns metadata envelopes without body content | -25% line floor; full-content artifacts permitted shorter forms |
any β minimal | β₯2 critical sources unavailable | -35% line floor; tradecraft (WEP/Admiralty/SAT) still mandatory |
degraded-* β full | Source recovers within run lifetime | Normally not transitioned β manifest records initial probe state |
𧬠Analysis Artifact State Machine
Each individual analysis artifact under analysis/daily/<YYYY-MM-DD>/<slug>/ progresses through a six-state lifecycle during Stage B. The catalog of 60 templates in analysis/templates/ seeds the Empty state; each template requires Pass-1 β Pass-2 work to reach Validated before Stage C accepts it.
stateDiagram-v2
[*] --> Empty: Stage B begins<br/>(template skeleton in analysis/templates/)
Empty --> Draft: AI agent reads methodology<br/>(per-artifact-methodologies.md)
Draft --> Pass1Complete: Initial content written<br/>(β₯60% of stage budget)
Pass1Complete --> Pass2Refined: Read-back and improve<br/>(β₯40% of stage budget)
Pass2Refined --> Validated: Local checks pass<br/>(line floor, mermaid syntax, sections)
Pass2Refined --> Pass2Refined: Self-revision loop<br/>(extend shallow sections)
Validated --> Committed: Written to analysis/daily/<date>/<slug>/<artifact>.md
Committed --> [*]: Listed in manifest.files for Stage C validation
Empty --> AbandonedSkip: Optional artifact deemed N/A
AbandonedSkip --> [*]: Marked as skipped in manifest
Draft --> Pass1Failed: Time budget exhausted before Pass 1
Pass1Complete --> Pass2Failed: Time budget exhausted before Pass 2
Pass1Failed --> [*]: Stage B fails, run aborted
Pass2Failed --> [*]: Stage C will RED on shallow content
note right of Pass1Complete
Quality floor signals:
- Mandatory sections present
- WEP/Admiralty grading
- β₯1 Mermaid diagram (per
artifact-catalog.md)
- No [AI_ANALYSIS_REQUIRED]
markers
end note
note right of Pass2Refined
Pass-2 read-back rule
(ai-driven-analysis-guide.md
Step 10):
Read every section word-by-word,
identify shallow content,
rewrite and extend.
Pass 2 is where quality is
achieved β not Pass 1.
end note
Artifact State Definitions
| State | Description | Validator outcome |
|---|---|---|
| Empty | Template skeleton from analysis/templates/ | Not yet present |
| Draft | Agent has begun writing, sections incomplete | RED on requiredSections |
| Pass-1 Complete | All sections present; quality may still be shallow | Possibly WARN on word-count |
| Pass-2 Refined | Read-back done; shallow sections extended | Likely passes line floor |
| Validated | Local Mermaid/section/floor checks pass | Local pass (no Stage-C run yet) |
| Committed | Written to disk and listed in manifest.files | Eligible for Stage-C scan |
| Abandoned/Skip | Optional artifact not produced (rare β most are required) | Not in manifest.files |
π΅οΈ Political Intelligence Artifact State Machine
For artifacts that carry political intelligence judgements (scenario-forecast.md, coalition-dynamics.md, wildcards-blackswans.md, intelligence-assessment.md, political-threat-landscape.md, executive-brief.md, synthesis-summary.md, methodology-reflection.md), the content additionally progresses through an OSINT-tradecraft state machine governed by analysis/methodologies/osint-tradecraft-standards.md.
stateDiagram-v2
[*] --> SourceCollection: Stage B begins
SourceCollection --> SourceGrading: Sources gathered
SourceGrading --> HypothesisGeneration: Admiralty A1βF6 grade assigned per source<br/>(reliability letter Γ credibility digit)
HypothesisGeneration --> ACHEvaluation: β₯3 plausible hypotheses identified
state ACHEvaluation {
[*] --> BuildingMatrix
BuildingMatrix --> CountingInconsistencies: hypotheses Γ evidence
CountingInconsistencies --> WinningHypothesis: fewest inconsistencies wins
CountingInconsistencies --> KeyAssumptionsCheck: parallel KAC
KeyAssumptionsCheck --> WinningHypothesis: assumptions documented
WinningHypothesis --> [*]
}
ACHEvaluation --> ConfidenceAssignment: hypothesis selected
ConfidenceAssignment --> WEPBanding: source grade Γ ACH outcome β confidence
state WEPBanding {
[*] --> SelectingBand
SelectingBand --> AlmostNoTermsForbidden: banned terms (likely-but-vague) replaced
AlmostNoTermsForbidden --> BandSelected: one of the seven Kent bands<br/>(remote β almost-certain)
BandSelected --> [*]
}
WEPBanding --> StructuredAnalyticTechniques: probability-banded judgement
state StructuredAnalyticTechniques {
[*] --> CoreSATsApplied
CoreSATsApplied --> SupportingSATsApplied: β₯10 core SATs applied
SupportingSATsApplied --> SATAttestation: methodology-reflection.md Β§3 table
SATAttestation --> [*]
}
StructuredAnalyticTechniques --> RedTeamReview: SAT attestation present
RedTeamReview --> PreMortem: devil's advocate written
PreMortem --> Publication: top-3 failure modes documented
Publication --> [*]: artifact passes Stage C tradecraft gates
SourceGrading --> InsufficientGrade: only D/E/F sources available
InsufficientGrade --> [*]: artifact downgraded to lower confidence
ACHEvaluation --> InsufficientHypotheses: <3 plausible hypotheses
InsufficientHypotheses --> Publication: justified in methodology-reflection.md
note right of SourceGrading
Admiralty Code (NATO STANAG 2511):
Reliability A (completely reliable) β F (cannot be judged)
Credibility 1 (confirmed) β 6 (cannot be judged)
See osint-tradecraft-standards.md Β§2
end note
note right of WEPBanding
Words of Estimative Probability
(Kent scale, ICD-203 Β§6):
Almost no chance (<5%)
Very unlikely (5β20%)
Unlikely (20β45%)
Roughly even chance (45β55%)
Likely (55β80%)
Very likely (80β95%)
Almost certain (>95%)
Banned: "possible", "could",
"may", uncalibrated "likely"
end note
note right of StructuredAnalyticTechniques
Required core SATs:
ACH, KAC, Quality of Information,
Indicators & Signposts, What-If,
High-Impact/Low-Probability,
Red Team / Devil's Advocate,
Pre-Mortem, Scenario Analysis,
Lightweight ACH per-file
Plus PESTLE, Stakeholder Mapping,
Bayesian Update, Force-Field,
Cone of Plausibility (supporting)
end note
Tradecraft Gate Outcomes (Stage C)
| Gate | Trigger | Severity |
|---|---|---|
| WEP missing | Probabilistic claim without WEP band | RED |
| Admiralty missing | Source cited without A1βF6 grade | RED |
| BLUF missing | Executive judgement absent from executive-brief.md | RED |
| <10 SATs attested | methodology-reflection.md Β§3 lists fewer than 10 SATs | RED |
| Banned WEP term | "possible", "could", "may" in analytic conclusion | RED |
| Reader-block | Sentence/paragraph length exceeds readability ceiling | WARN (RED in --strict) |
| Source-diversity warning | Single source dominates evidence base | WARN (RED in --strict) |
π¨ Color Legend & Styling
State diagrams use consistent colors to indicate state categories:
stateDiagram-v2
[*] --> Normal: Normal States
[*] --> Transient: Transient States
[*] --> Error: Error States
[*] --> Success: Success States
[*] --> Critical: Critical States
state Normal {
[*] --> Processing
[*] --> Waiting
[*] --> Active
}
state Transient {
[*] --> Connecting
[*] --> Retrying
[*] --> Loading
}
state Error {
[*] --> Failed
[*] --> Rejected
[*] --> Invalid
}
state Success {
[*] --> Complete
[*] --> Validated
[*] --> Published
}
state Critical {
[*] --> Fatal
[*] --> Aborted
[*] --> SecurityViolation
}
note right of Normal
Light blue/gray:
Regular processing states
end note
note right of Transient
Yellow/amber:
Temporary states during
transitions
end note
note right of Error
Red/pink:
Error states requiring
attention
end note
note right of Success
Green:
Successfully completed
states
end note
note right of Critical
Dark red:
Critical failures requiring
immediate intervention
end note
| Color | State Type | Example States |
|---|---|---|
| π΅ Light Blue | Normal Processing | Active, Generating, Processing |
| π‘ Yellow | Transient | Connecting, Retrying, Loading |
| π’ Green | Success | Complete, Validated, Published, Deployed |
| π΄ Red | Error | Failed, Rejected, Invalid |
| β« Dark Red | Critical | Fatal, Aborted, SecurityViolation |
| βͺ White | Initial/Final | [*] start and end states |
π State Metrics & Monitoring
Key Performance Indicators
| Metric | Target | Measurement | Alert Threshold |
|---|---|---|---|
| Time in Idle | >95% | Percentage of time waiting | <90% (overloaded) |
| Initialization Success Rate | >99% | Successful init / total attempts | <95% |
| MCP Connection Success Rate | >95% | Connected / connection attempts | <90% |
| Article Generation Success Rate | >98% | Published / attempted | <95% |
| Validation Pass Rate | >99% | Passed / total validations | <98% |
| Deployment Success Rate | >99% | Successful deploys / attempts | <98% |
| Error Recovery Rate | >90% | Recovered / total errors | <80% |
| Fallback Activation Rate | <5% | Fallback / total attempts | >10% |
State Duration Targets
| State | Target Duration | Warning Threshold | Error Threshold |
|---|---|---|---|
| Initialization | <30s | >45s | >60s |
| MCP Connection | <10s | >20s | >30s |
| Data Fetching | <30s | >60s | >90s |
| Article Generation | <120s | >180s | >300s |
| Validation | <30s | >45s | >60s |
| Testing | <60s | >90s | >120s |
| Git Operations | <30s | >45s | >60s |
| GitHub Pages Deploy | <90s | >150s | >300s |
Monitoring Commands
# Check current workflow state
gh workflow view news-generation --repo Hack23/euparliamentmonitor
# View recent workflow runs
gh run list --workflow=news-generation.yml --limit 20
# Monitor specific run state
gh run watch <run-id>
# Check GitHub Pages deployment status
gh api repos/Hack23/euparliamentmonitor/pages/builds/latest
# View state transition logs
gh run view <run-id> --log
π Security State Considerations
State-Based Security Controls
- Immutable States: Once
ArticlePublished, content cannot be modified (only reverted) - Validation Gates: Cannot transition to
Publishingwithout passingValidating - Authentication States: MCP connection requires successful authentication
- Rate Limiting: Retry states implement exponential backoff to prevent DoS
- Error Isolation: Error states log details but don't expose sensitive information
- Audit Trail: All state transitions logged with timestamps and context
Compliance Requirements
Per Hack23 ISMS State Management Policy:
- ISO 27001 A.8.2: All state transitions must be logged and auditable
- ISO 27001 A.12.4: States must prevent unauthorized data modification
- ISO 27001 A.14.2: State validation ensures data integrity
- NIS2 Article 21: Error states must trigger incident response procedures
π Related Documentation
Process Documents
- FLOWCHART.md: Detailed process flows for news generation
- SECURITY_ARCHITECTURE.md: Security controls and threat model
Data Documents
- DATA_MODEL.md: Entity relationships and data structures
- ARCHITECTURE.md: C4 model system architecture
Strategic Documents
- MINDMAP.md: Conceptual system relationships
- SWOT.md: Strategic analysis and opportunities
π Footer
Document Classification: Public
ISMS Compliance: ISO 27001:2022, NIST CSF 2.0, CIS Controls v8.1, GDPR, NIS2, EU CRA aligned
Technology Stack: Node.js 26, TypeScript 6.0.3, gh-aw v0.77.3, AWS S3 + CloudFront, GitHub Pages (fallback), EP MCP 1.3.12, WB MCP 1.0.1, IMF REST SDMX 3.0
Architecture Pattern: Static Site Generator with Agentic AI-First Authoring and Zero Runtime Dependencies
Review Status: Active, next review 2026-08-30
π Related ISMS-PUBLIC Policies
π State Diagrams β Behavioral Model for EU Parliament Monitor
Part of ISMS-compliant Architecture Documentation Suite
ποΈ GitHub Repository β’ π‘οΈ ISMS Framework β’ π Hack23