name: Conversation lifecycle (informational)

# Scoped to the code this browser gate actually exercises — the chat
# render/streaming surface — so it doesn't spin up playwright+chromium on
# docs-only or unrelated changes. If none of these paths change, the run is
# skipped entirely (GitHub treats a path-filtered no-match as "not triggered").
on:
  pull_request:
    branches: [master]
    paths:
      - 'static/**'
      - 'api/**.py'
      - 'server.py'
      - 'tests/browser_conversation_lifecycle.py'
      - 'tests/sidebar_terminal_barrier_server.py'
      - 'tests/browser_historical_transcript_hydration.py'
      - 'tests/browser_reconnect_scene_redraw.py'
      - 'requirements*.txt'
      - 'pyproject.toml'
      - '.github/workflows/conversation-lifecycle.yml'
  push:
    branches: [master]
    paths:
      - 'static/**'
      - 'api/**.py'
      - 'server.py'
      - 'tests/browser_conversation_lifecycle.py'
      - 'tests/sidebar_terminal_barrier_server.py'
      - 'tests/browser_historical_transcript_hydration.py'
      - 'tests/browser_reconnect_scene_redraw.py'
      - 'requirements*.txt'
      - 'pyproject.toml'
      - '.github/workflows/conversation-lifecycle.yml'

jobs:
  live-to-final:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    # Keep existing proof rows informational; reconnect regressions fail CI.
    continue-on-error: ${{ matrix.name != 'reconnect-scene-redraw' }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: normal
            script: tests/browser_conversation_lifecycle.py
            scenario: normal
          - name: terminal-error
            script: tests/browser_conversation_lifecycle.py
            scenario: terminal-error
          - name: historical-transcript-hydration
            script: tests/browser_historical_transcript_hydration.py
          - name: reconnect-scene-redraw
            script: tests/browser_reconnect_scene_redraw.py
            browsers: chromium
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'
          cache: 'pip'
          cache-dependency-path: |
            **/requirements*.txt
            **/pyproject.toml
            .github/workflows/conversation-lifecycle.yml

      - name: Install browser gate dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt playwright
          python -m playwright install --with-deps chromium

      - name: Run conversation lifecycle gate
        env:
          LIFECYCLE_ARTIFACT_DIR: lifecycle-artifacts
          HISTORICAL_HYDRATION_ARTIFACT_DIR: lifecycle-artifacts
          LIFECYCLE_SCENARIO: ${{ matrix.scenario }}
          BROWSERS: ${{ matrix.browsers }}
        run: python ${{ matrix.script }}

      - name: Run settlement frame proof
        if: matrix.scenario == 'normal'
        env:
          LIFECYCLE_ARTIFACT_DIR: lifecycle-artifacts
          LIFECYCLE_SCENARIO: normal
          LIFECYCLE_TEST_BITE: settle-worklog-frame-proof
        run: python tests/browser_conversation_lifecycle.py

      - name: Recover a missing terminal frame
        if: matrix.scenario == 'normal'
        env:
          LIFECYCLE_ARTIFACT_DIR: lifecycle-artifacts/missing-terminal
          LIFECYCLE_SCENARIO: normal
          LIFECYCLE_TEST_BITE: sidebar-idle-missing-terminal
        run: python tests/browser_conversation_lifecycle.py

      - name: Upload failure artifacts
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: conversation-lifecycle-failure-${{ matrix.name }}
          path: lifecycle-artifacts
          if-no-files-found: ignore
