bug: read-only volume mount prevents scorecard tracker from persisting state #85

Closed
opened 2026-03-17 18:03:56 +00:00 by cal · 1 comment
Owner

Problem

The data/ directory is mounted read-only in docker-compose.yml:

volumes:
  - ${SHEETS_CREDENTIALS_HOST_PATH:-./data}:/app/data:ro

This protects the Google Sheets credentials file, but it also prevents runtime state files from being written. ScorecardTracker.save_data() silently fails (caught by a bare except), so:

  • unpublish_scorecard() removals are never persisted to disk
  • Completed games accumulate in scorecards.json indefinitely
  • The live scorebug tracker re-reads stale entries every 3-minute loop, hitting Google Sheets APIs for games that ended days ago
  • The #live-sba-scores channel gets cleared and hidden on repeat

Same issue likely affects other state files in storage/: voice_channels.json, trade_channels.json, soak_data.json.

How it was discovered

After the 2026.3.17 release, the live scorebug tracker kept updating despite no active games. Found 16 stale scorecard entries dating back to March 9. Cleared manually on akamai.

Fix

Split the volume mount so credentials are read-only but runtime state is writable. Two options:

  1. Separate volumes: Mount credentials file directly (:ro) and mount a writable volume for state files

    volumes:
      - ./credentials.json:/app/data/credentials.json:ro
      - major-domo-state:/app/storage
    
  2. Move state directory: Have trackers write to a different path (e.g. /app/state/) with its own writable volume, keeping data/ entirely read-only for credentials

Also: the except Exception in save_data() should at minimum log the error instead of silently swallowing it.

## Problem The `data/` directory is mounted read-only in `docker-compose.yml`: ```yaml volumes: - ${SHEETS_CREDENTIALS_HOST_PATH:-./data}:/app/data:ro ``` This protects the Google Sheets credentials file, but it also prevents runtime state files from being written. `ScorecardTracker.save_data()` silently fails (caught by a bare `except`), so: - `unpublish_scorecard()` removals are never persisted to disk - Completed games accumulate in `scorecards.json` indefinitely - The live scorebug tracker re-reads stale entries every 3-minute loop, hitting Google Sheets APIs for games that ended days ago - The `#live-sba-scores` channel gets cleared and hidden on repeat Same issue likely affects other state files in `storage/`: `voice_channels.json`, `trade_channels.json`, `soak_data.json`. ## How it was discovered After the 2026.3.17 release, the live scorebug tracker kept updating despite no active games. Found 16 stale scorecard entries dating back to March 9. Cleared manually on akamai. ## Fix Split the volume mount so credentials are read-only but runtime state is writable. Two options: 1. **Separate volumes**: Mount credentials file directly (`:ro`) and mount a writable volume for state files ```yaml volumes: - ./credentials.json:/app/data/credentials.json:ro - major-domo-state:/app/storage ``` 2. **Move state directory**: Have trackers write to a different path (e.g. `/app/state/`) with its own writable volume, keeping `data/` entirely read-only for credentials Also: the `except Exception` in `save_data()` should at minimum log the error instead of silently swallowing it.
Claude added the
ai-working
label 2026-03-17 18:31:14 +00:00
Claude added the
status/in-progress
label 2026-03-17 18:32:59 +00:00
Claude removed the
status/in-progress
label 2026-03-17 18:35:09 +00:00
Collaborator

PR #86 opened: #86

Fix approach: Split the single :ro data volume into two separate mounts:

  1. Credentials file mounted read-only at file level (./data/major-domo-service-creds.json/app/data/major-domo-service-creds.json:ro)
  2. New writable ./storage volume for all runtime state files (/app/storage:rw)

All 5 tracker defaults updated (scorecards.json, voice_channels.json, trade_channels.json, soak_data.json) to write to storage/ instead of data/. The save_data() methods already log errors properly — the :ro mount was the only thing preventing writes.

Deployment action needed: Update .env on akamai to set SHEETS_CREDENTIALS_HOST_PATH=./data/major-domo-service-creds.json and add STATE_HOST_PATH=./storage.

PR #86 opened: https://git.manticorum.com/cal/major-domo-v2/pulls/86 **Fix approach**: Split the single `:ro` data volume into two separate mounts: 1. Credentials file mounted read-only at file level (`./data/major-domo-service-creds.json` → `/app/data/major-domo-service-creds.json:ro`) 2. New writable `./storage` volume for all runtime state files (`/app/storage:rw`) All 5 tracker defaults updated (`scorecards.json`, `voice_channels.json`, `trade_channels.json`, `soak_data.json`) to write to `storage/` instead of `data/`. The `save_data()` methods already log errors properly — the `:ro` mount was the only thing preventing writes. **Deployment action needed**: Update `.env` on akamai to set `SHEETS_CREDENTIALS_HOST_PATH=./data/major-domo-service-creds.json` and add `STATE_HOST_PATH=./storage`.
Claude added
status/pr-open
ai-pr-opened
and removed
ai-working
labels 2026-03-17 18:35:32 +00:00
cal closed this issue 2026-03-20 15:28:15 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/major-domo-v2#85
No description provided.