STATEDIAGRAM.md

May 30, 2026 Β· View on GitHub

Hack23 Logo

πŸ”„ EU Parliament Monitor β€” State Diagrams

πŸ“Š System State Transitions and Lifecycle Management
🎯 Behavioral Model for Static News Generation Platform

Owner Version Effective Date Review Cycle

πŸ“‹ 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

DocumentFocusDescriptionDocumentation Link
ArchitectureπŸ›οΈ ArchitectureC4 model showing current system structureView Source
Future ArchitectureπŸ›οΈ ArchitectureC4 model showing future system structureView Source
Mindmaps🧠 ConceptCurrent system component relationshipsView Source
Future Mindmaps🧠 ConceptFuture capability evolutionView Source
SWOT AnalysisπŸ’Ό BusinessCurrent strategic assessmentView Source
Future SWOT AnalysisπŸ’Ό BusinessFuture strategic opportunitiesView Source
Data ModelπŸ“Š DataCurrent data structures and relationshipsView Source
Future Data ModelπŸ“Š DataEnhanced European Parliament data architectureView Source
FlowchartsπŸ”„ ProcessCurrent data processing workflowsView Source
Future FlowchartsπŸ”„ ProcessEnhanced AI-driven workflowsView Source
State DiagramsπŸ”„ BehaviorCurrent system state transitionsView Source
Future State DiagramsπŸ”„ BehaviorEnhanced adaptive state transitionsView Source
Security ArchitectureπŸ›‘οΈ SecurityCurrent security implementationView Source
Future Security ArchitectureπŸ›‘οΈ SecuritySecurity enhancement roadmapView Source
Threat Model🎯 SecuritySTRIDE threat analysisView Source
Classification🏷️ GovernanceCIA classification & BCPView Source
CRA AssessmentπŸ›‘οΈ ComplianceCyber Resilience ActView Source
Workflowsβš™οΈ DevOpsCI/CD documentationView Source
Future WorkflowsπŸš€ DevOpsPlanned CI/CD enhancementsView Source
Business Continuity PlanπŸ”„ ResilienceRecovery planningView Source
Financial Security PlanπŸ’° FinancialCost & security analysisView Source
End-of-Life StrategyπŸ“¦ LifecycleTechnology EOL planningView Source
Unit Test PlanπŸ§ͺ TestingUnit testing strategyView Source
E2E Test PlanπŸ” TestingEnd-to-end testingView Source
Performance Testing⚑ PerformancePerformance benchmarksView Source
Security PolicyπŸ”’ SecurityVulnerability reporting & security policyView Source

πŸ›‘οΈ ISMS Policy Alignment

This state diagram documentation implements controls aligned with Hack23 AB's publicly available ISMS framework.

Applicable ISMS Policies

PolicyRelevance
Secure Development PolicyState management follows secure SDLC lifecycle
Information Security PolicySystem state transitions comply with security governance
Incident Response PlanError and failure states trigger incident response procedures
Change Management PolicyDeployment 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:

  1. Define Valid State Transitions: Document legal state changes and their triggers
  2. Lifecycle Management: Show complete entity lifecycles from creation to archival
  3. Error Handling: Illustrate error states and recovery paths
  4. Concurrency Control: Define states that prevent race conditions
  5. 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

StateDescriptionEntry ConditionsExit ConditionsTimeout
IdleSystem waiting for triggerPrevious workflow complete OR system startupSchedule reached OR manual dispatchN/A
InitializingLoading configuration and environmentWorkflow triggeredConfig loaded successfully30s
ConfigurationLoadingReading package.json, .env filesInitialization startedConfig parsed and validated10s
EnvironmentValidationChecking environment variables, Node versionConfig loadedEnvironment meets requirements10s
DependencyCheckVerifying npm packages installedEnvironment validatedAll deps available OR missing deps identified15s
DependencyInstallRunning npm ci to install packagesMissing dependencies detectedInstallation complete180s
InitializationFailedFatal error during startupRepeated failures, missing critical configWorkflow terminatesN/A
ReadySystem prepared to execute generationAll checks passedData source connection initiated5s
MCPConnectionConnecting to European Parliament MCP ServerReady state achievedConnected OR fallback mode30s
DataFetchingRetrieving parliamentary data via MCPMCP connectedData retrieved OR fallback60s
GeneratingCreating multi-language articlesData availableAll articles generated300s
GeneratingFallbackCreating placeholder articlesMCP unavailablePlaceholder articles generated60s
ValidatingRunning HTML validation, schema checksGeneration completeValidation passed OR failed45s
ValidationFailedDetected invalid outputValidation checks failedRetry generation OR abort10s
TestingExecuting ESLint, tests, security scansValidation passedTests passed OR failed120s
TestFailedTest suite failures detectedTest execution failedWorkflow aborted10s
PublishingCommitting and pushing to GitTests passedGit push successful OR failed30s
PublishFailedGit push failedGit operation failedRetry OR abort10s
DeployedChanges pushed to GitHubGit push successfulGitHub Pages deployment initiated5s
MonitoringAwaiting GitHub Pages deploymentDeployedDeployment complete180s

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

StateDescriptionDurationRollback Possible
ArticlePendingArticle scheduled for generation0-60sYes
DataCollectingFetching source data from EP APIs10-60sYes
ContentGenerationLLM creating article content15-120sYes
ArticleDraftInitial content created0-5sYes
LanguageProcessingTranslating to all languages30-300sYes
ArticleValidationRunning validation checks10-30sYes
ArticleRejectedFailed validationUntil fixedYes
ArticleAbandonedPermanently failedPermanentNo
ArticleValidatedPassed all checks0-5sYes
ArticleStagingReady for commit0-10sYes
ArticlePublishedCommitted to GitPermanentNo*
ArticleIndexedAdded to language indexesPermanentNo
ArticleLiveDeployed on GitHub PagesUntil archivedNo
ArticleMonitoredActive monitoring90 daysNo
ArticleArchivedMoved to archivePermanentNo

*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

StateDescriptionTimeoutRecovery Action
DisconnectedNo active connectionN/AInitialize connection
ConnectingTCP/stdio connection in progress10sRetry with backoff
AuthenticatingMCP handshake and auth5sRetry auth
ConnectionTimeoutConnection attempt exceeded timeoutN/AEnter retry wait
AuthFailedAuthentication rejectedN/ACheck credentials, retry
RetryWaitExponential backoff delay1s, 2s, 4sRetry connecting
ConnectedMCP handshake completeN/AProceed to health check
HealthyServer health verifiedN/ATransition to active
ActiveReady for tool requestsN/AProcess requests
RequestSendingTool call in progress30sRetry on timeout
RequestFailedRequest failedN/ARetry or degrade
DegradedPersistent errors detectedN/AAttempt reconnection
ReconnectingAttempting to restore connection10sReconnect or disconnect
FallbackModeUsing placeholder contentN/AContinue 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 TypeChecks PerformedFailure ActionRetry Allowed
Schema ValidationJSON structure, types, required fields, constraintsLog error, reject dataYes (1 retry)
Content ValidationHTML sanitization, link validation, length checksLog error, sanitize or rejectYes (auto-fix)
Security ValidationXSS, SQLi, CSRF, clickjacking, CSP violationsLog error, reject contentNo
HTML ValidationParse errors, doctype, meta tags, semantics, accessibilityLog error, auto-fix or rejectYes (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 TypeSeverityRetry StrategyFallbackAlert
Network ErrorTransient3 retries, exponential backoffContinue with cacheNo
Timeout ErrorTransient3 retries, extended timeoutSkip operationNo
Rate Limit ErrorTransientWait + retry (per X-RateLimit headers)Queue for laterNo
Service UnavailableTransient3 retries, exponential backoffUse fallback serviceWarning
Validation ErrorPersistent1 retry with fixUse last valid dataWarning
Configuration ErrorPersistentNo retryUse defaultsError
Data Quality ErrorPersistentNo retrySkip corrupt dataWarning
Authentication ErrorPersistent1 retryAbort workflowError
System ErrorFatalNo retryAbortCritical
Security ViolationFatalNo retryAbortCritical
Data CorruptionFatalNo retryAbortCritical
Resource ExhaustionFatalNo retryAbortCritical

πŸ“¦ 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

StateDescriptionDurationRollback
PreDeploymentFinal checks before commit5sYes
GitStagingAdding files to Git index10sYes
GitCommitCreating signed commit5sYes
GitPushPushing to GitHub remote10-30sNo*
GitHubPagesQueueGitHub Pages build queue30-90sNo
BuildingJekyll build process30-60sNo
DeployingCDN deployment30-60sNo
DeploymentCompleteLive on GitHub PagesPermanentNo
VerifyDeploymentPost-deploy validation30sN/A
DeploymentMonitoredMonitoring activeOngoingN/A
DeploymentFailedCritical failureN/ARollback
DeploymentDegradedPartial failureUntil fixedManual

*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

CategoryTriggerRemediation
MissingManifestAnalysis stage did not emit required intelligence filesRe-run analysis stage with longer time budget
InsufficientReferencesWord-count thresholds not metExtend AI reasoning; verify Pass-2 improvement actually ran
FallbackLeakAI_ANALYSIS_REQUIRED / AI_MARKER sentinels present in rendered HTMLAgent author must fill slots directly; re-run generate stage
MissingEconomicContextBoth WB and IMF unavailableWait 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

StageDescriptionOutputGate
AData acquisition (EP MCP + IMF + World Bank)Cached envelopes, manifest with dataModeAll sources probed, dataMode resolved
BAnalysis (2-pass) β€” produces 39+ artifacts under analysis/daily/Methodology-driven artifact set with WEP/Admiralty gradingPass 2 read-back complete
CCompleteness gate (scripts/validate-analysis-completeness.js)STAGE_C_GATE:GREEN/RED stdout + manifest.history[].gateResultRED blocks PR; GREEN allows Stage D
DArticle generation (2-pass + deterministic aggregator render)One HTML article in EN under news/<slug>/<date>/article.htmlAggregator render succeeds
ESingle PR creation via safeoutputs___create_pull_requestPR with analysis artifacts + article HTML, exactly one callHard 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 β†’ ToTriggerValidator behaviour
full β†’ degraded-imfcache/imf/imf-probe-summary.json reports failure or is missing-15% line floor; IMF citation requirement falls back to WB
full β†’ degraded-votingVote tool (get_voting_records / get_latest_votes) times out-15% line floor; voting-pattern artifacts use cached sample
full β†’ title-onlyEP 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-* β†’ fullSource recovers within run lifetimeNormally 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

StateDescriptionValidator outcome
EmptyTemplate skeleton from analysis/templates/Not yet present
DraftAgent has begun writing, sections incompleteRED on requiredSections
Pass-1 CompleteAll sections present; quality may still be shallowPossibly WARN on word-count
Pass-2 RefinedRead-back done; shallow sections extendedLikely passes line floor
ValidatedLocal Mermaid/section/floor checks passLocal pass (no Stage-C run yet)
CommittedWritten to disk and listed in manifest.filesEligible for Stage-C scan
Abandoned/SkipOptional 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)

GateTriggerSeverity
WEP missingProbabilistic claim without WEP bandRED
Admiralty missingSource cited without A1–F6 gradeRED
BLUF missingExecutive judgement absent from executive-brief.mdRED
<10 SATs attestedmethodology-reflection.md Β§3 lists fewer than 10 SATsRED
Banned WEP term"possible", "could", "may" in analytic conclusionRED
Reader-blockSentence/paragraph length exceeds readability ceilingWARN (RED in --strict)
Source-diversity warningSingle source dominates evidence baseWARN (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
ColorState TypeExample States
πŸ”΅ Light BlueNormal ProcessingActive, Generating, Processing
🟑 YellowTransientConnecting, Retrying, Loading
🟒 GreenSuccessComplete, Validated, Published, Deployed
πŸ”΄ RedErrorFailed, Rejected, Invalid
⚫ Dark RedCriticalFatal, Aborted, SecurityViolation
βšͺ WhiteInitial/Final[*] start and end states

πŸ“Š State Metrics & Monitoring

Key Performance Indicators

MetricTargetMeasurementAlert 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

StateTarget DurationWarning ThresholdError 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

  1. Immutable States: Once ArticlePublished, content cannot be modified (only reverted)
  2. Validation Gates: Cannot transition to Publishing without passing Validating
  3. Authentication States: MCP connection requires successful authentication
  4. Rate Limiting: Retry states implement exponential backoff to prevent DoS
  5. Error Isolation: Error states log details but don't expose sensitive information
  6. 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

Process Documents

Data Documents

Strategic Documents

  • MINDMAP.md: Conceptual system relationships
  • SWOT.md: Strategic analysis and opportunities

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


πŸ”„ State Diagrams β€” Behavioral Model for EU Parliament Monitor
Part of ISMS-compliant Architecture Documentation Suite

πŸ›οΈ GitHub Repository β€’ πŸ›‘οΈ ISMS Framework β€’ 🌐 Hack23