Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1b1102a
feat: day-one quick-win bundle (QW3/4/7/9) from the 2026-07 review
Jul 8, 2026
ecb060f
test+docs: extend QW-bundle coverage + reconcile related docs
Jul 8, 2026
2b5a158
refactor(D5.1/QW10): single utils/ndjsonStream.ts, replace 5 parser c…
Jul 8, 2026
8027a7f
feat(D5.2): typed notification store replaces the dual toast channels
Jul 8, 2026
90d867c
feat(D5.3): cancellable analysis via AbortController + visible Cancel
Jul 8, 2026
b925be9
docs(D5): document the streaming + notification pipeline
Jul 8, 2026
adf797b
refactor(D4): extract useManualSimulation hook from App.tsx
Jul 8, 2026
e71cd2e
feat(D7): deployment lockdown profile + test-gated deploy & rollback
Jul 8, 2026
605b8e2
refactor(D4c): split useDiagrams into per-domain sub-hooks (facade-pr…
Jul 9, 2026
8e4c25e
refactor(D4d): consolidate VisualizationPanel's SLD-edit props into o…
Jul 9, 2026
e1c2f53
docs(D4): record the useDiagrams split + props consolidation
Jul 9, 2026
d978b34
refactor(D4): consolidate remaining VisualizationPanel + ActionFeed p…
Jul 9, 2026
df66d81
test(D4): explicit grouped-prop contract tests for the consolidated p…
Jul 9, 2026
b33e8b0
perf(D6): SVG element-adoption pipeline — parse once, adopt directly
Jul 9, 2026
3b599ff
feat(D8): reproducible data + Codabench scorer parity supply chain
Jul 9, 2026
89eb600
docs(review): add at-a-glance status table + consolidated "What's left"
Jul 9, 2026
9719165
perf(qw): vectorize _diff_switches (QW11), LRU-cap action-diagram cac…
Jul 9, 2026
bc8cc37
fix(qw): single Overflow_Graph anchor + reset() completeness (QW17) +…
Jul 9, 2026
370dfa0
feat(qw): modal keyboard/focus hook (QW20), detached-popup theming (Q…
Jul 9, 2026
f5634e1
feat(qw): error-leak hardening (QW6), recommender pin + canary (QW8),…
Jul 9, 2026
8ba8291
feat(game-mode): session-log replay to derive trusted scores (FU-2)
Jul 9, 2026
66a9072
feat(docs): gate the CLAUDE.md inventory against drift (D9)
Jul 9, 2026
78a1c90
docs: track remaining deep-revision tails as in-repo issues (FU-5..FU-8)
Jul 9, 2026
fc57569
Release 0.9.0: consolidate 2026-07 review revisions + QW/FU-2/D9
Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 0 additions & 99 deletions .circleci/config.yml

This file was deleted.

5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ test-results
# Docs and the frozen legacy mirror are not needed at runtime.
docs
standalone_interface_legacy.html

# Test suites are dead weight in the runtime image (QW25) — the app never
# imports them, and `COPY expert_backend/` would otherwise carry tests/ along.
expert_backend/tests
expert_backend/test_backend.py
15 changes: 13 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
# Co-Study4Grid backend environment variables
# Copy to `.env` (ignored by git) or export directly in your shell.

# Comma-separated list of allowed CORS origins (default: "*" wide-open dev mode).
# Comma-separated list of allowed CORS origins. Default (unset): the local
# Vite dev/preview origins on loopback (localhost/127.0.0.1 :5173 and :4173).
# Set to the browser origin of the frontend in non-local deployments, e.g.
# CORS_ALLOWED_ORIGINS=https://costudy.example.com,https://ops.example.com
CORS_ALLOWED_ORIGINS=*
# Wide-open dev mode is now explicit opt-in (a wildcard lets any web page read
# /api/* off a localhost backend):
# CORS_ALLOWED_ORIGINS=*
# CORS_ALLOWED_ORIGINS=

# Deployment lockdown (D7): when truthy (1/true/yes/on), disable the
# desktop-era filesystem RPCs (custom config-file path, session
# save/list/load, native file picker) with a 403 {code: LOCKED_DOWN}.
# The Dockerfile sets this for the public HuggingFace Space; leave it
# unset for local/dev installs. Read-only app config stays available.
# COSTUDY4GRID_LOCKDOWN=1

# pypowsybl load-flow fast mode toggle (also set per-study from the UI).
# Unset or empty = default; "1" / "true" = enabled; "0" / "false" = disabled.
Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/canary.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Recommender canary

# QW8: PR/deploy installs pin expert_op4grid_recommender (recommender-pin.txt).
# This weekly canary floats to the LATEST release and runs the backend suite,
# so a breaking upstream release surfaces here (a red canary = "bump the pin
# after checking") instead of turning an unrelated PR red or shipping a
# regressed image on a zero-change rebuild.

on:
schedule:
- cron: '0 6 * * 1' # Mondays 06:00 UTC
workflow_dispatch: {}

jobs:
canary:
name: Backend tests against latest recommender
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: "3.10"
cache: 'pip'
- name: Install dependencies (float recommender to latest)
run: |
python -m pip install --upgrade pip
pip install ".[test]"
# Deliberately NOT pinned: resolve the newest published release.
pip install --no-deps --no-cache-dir --upgrade "expert_op4grid_recommender"
- name: Show resolved recommender version
run: pip show expert_op4grid_recommender | grep -i version
- name: Run backend Pytest (excluding graphviz-dependent tests)
run: pytest --ignore=expert_backend/tests/test_overflow_html_dim_logic.py
10 changes: 8 additions & 2 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ jobs:
- name: Run code-quality gate
run: python scripts/check_code_quality.py

- name: Run reporter unit tests
run: pytest scripts/test_code_quality_report.py -q
- name: Run docs-tree gate (D9)
# Fails when a CLAUDE.md reference points at a file that no longer exists
# or reintroduces a rotting `file.py:NNN` line anchor. See
# docs/architecture/code-quality-analysis.md §23.
run: python scripts/check_docs_tree.py

- name: Run reporter + docs-tree unit tests
run: pytest scripts/test_code_quality_report.py scripts/test_check_docs_tree.py -q

- name: Run mypy (gate)
# GATES the build: the shared-state base (services/_recommender_state.py)
Expand Down
50 changes: 45 additions & 5 deletions .github/workflows/deploy-huggingface.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ name: Deploy to HuggingFace Space
# The job no-ops (does not fail) when HF_TOKEN / HF_SPACE are absent, so the
# workflow is inert until you opt in by setting them.

# Test-gated (D7): deploy runs ONLY after the "Tests" workflow completes
# successfully on main — a green build is the gate, not just a merge. A
# manual `workflow_dispatch` (optionally from an older commit) is the
# rollback path; see deploy/huggingface/SETUP.md → "Rolling back".
on:
push:
workflow_run:
workflows: [ "Tests" ]
types: [ completed ]
branches: [ main ]
workflow_dispatch: {}

Expand All @@ -26,10 +32,18 @@ concurrency:
group: huggingface-space-deploy
cancel-in-progress: true

permissions:
contents: write # push the per-deploy rollback tag back to origin

jobs:
deploy:
name: Push snapshot to HF Space
runs-on: ubuntu-latest
# workflow_run fires on completion regardless of result — only deploy a
# SUCCESSFUL Tests run. workflow_dispatch always proceeds (rollback).
if: >-
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
steps:
- name: Check the deploy is configured
id: guard
Expand All @@ -44,10 +58,18 @@ jobs:
echo "configured=true" >> "$GITHUB_OUTPUT"
fi

- name: Checkout current tree + LFS objects
# The tested commit: the head of the Tests run (workflow_run), or the
# dispatched ref (workflow_dispatch / rollback).
- name: Resolve the deployed commit
if: steps.guard.outputs.configured == 'true'
id: sha
run: echo "sha=${{ github.event.workflow_run.head_sha || github.sha }}" >> "$GITHUB_OUTPUT"

- name: Checkout the tested tree + LFS objects
if: steps.guard.outputs.configured == 'true'
uses: actions/checkout@v4
with:
ref: ${{ steps.sha.outputs.sha }}
lfs: true
fetch-depth: 1 # an orphan snapshot only needs the current tree

Expand All @@ -60,14 +82,16 @@ jobs:

- name: Build a history-free snapshot
if: steps.guard.outputs.configured == 'true'
env:
DEPLOY_SHA: ${{ steps.sha.outputs.sha }}
run: |
cp deploy/huggingface/README.md README.md # HF needs the frontmatter at repo root
git checkout --orphan hf-deploy
git add -A
# Drop inert local dev artifacts from the deployed snapshot.
git rm -q --cached --ignore-unmatch \
.claude/plan.md inspect_action.py profiling_patch_results.json || true
git commit -q -m "Deploy ${GITHUB_SHA::7}"
.claude/plan.md profiling_patch_results.json || true
git commit -q -m "Deploy ${DEPLOY_SHA::7}"
test "$(git rev-list --count HEAD)" -eq 1 # sanity: exactly one commit

- name: Push to the HuggingFace Space
Expand All @@ -76,9 +100,25 @@ jobs:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
HF_SPACE: ${{ vars.HF_SPACE }}
HF_USERNAME: ${{ vars.HF_USERNAME }}
DEPLOY_SHA: ${{ steps.sha.outputs.sha }}
run: |
user="${HF_USERNAME:-${HF_SPACE%%/*}}"
# The token is a GitHub secret → masked in logs even inside the URL.
git remote add space "https://${user}:${HF_TOKEN}@huggingface.co/spaces/${HF_SPACE}"
git -c protocol.version=0 push -f space hf-deploy:main
echo "::notice::Pushed snapshot of ${GITHUB_SHA::7} to spaces/${HF_SPACE}; HF will rebuild."
echo "::notice::Pushed snapshot of ${DEPLOY_SHA::7} to spaces/${HF_SPACE}; HF will rebuild."

# Rollback pointer (D7): tag the exact commit deployed to the Space,
# so a bad deploy can be reverted by re-dispatching this workflow from
# a prior `space-deploy-*` tag. The Space push itself is force-pushed
# and history-free, so this origin tag is the only durable record of
# what shipped. Never fails the deploy.
- name: Tag the deployed commit on origin
if: steps.guard.outputs.configured == 'true'
env:
DEPLOY_SHA: ${{ steps.sha.outputs.sha }}
run: |
tag="space-deploy-$(date -u +%Y%m%d-%H%M%S)-${DEPLOY_SHA::7}"
git tag -a "$tag" "$DEPLOY_SHA" -m "Deployed to HF Space" || { echo "::warning::tag create failed"; exit 0; }
git push origin "refs/tags/$tag" || echo "::warning::tag push failed (non-fatal)"
echo "::notice::Tagged deployed commit as $tag"
57 changes: 43 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install ".[test]"
# Track the latest published expert_op4grid_recommender release: the
# >=0.2.4 floor documents the minimum the GST / superposition tests
# need, and pip + --no-cache-dir always resolve to the newest release
# above it (no stale pinned version to bump). --no-deps skips the
# recommender's heavy transitive stack (pypowsybl already comes from
# co_study4grid's own dependencies).
pip install --no-deps --no-cache-dir "expert_op4grid_recommender>=0.2.4"
# Pin expert_op4grid_recommender to the exact version in
# recommender-pin.txt (QW8) so an upstream release can't silently turn
# a green PR red; the weekly canary.yml floats to latest and flags
# regressions. --no-deps skips the recommender's heavy transitive
# stack (pypowsybl already comes from co_study4grid's own deps).
pip install --no-deps -r recommender-pin.txt
- name: Run Pytest (excluding graphviz-dependent tests)
# Coverage GATES at fail_under=72 (pyproject [tool.coverage.report]).
# See docs/architecture/code-quality-analysis.md §20.
Expand All @@ -51,6 +50,37 @@ jobs:
if-no-files-found: ignore
retention-days: 30

# ------------------------------------------------------------------
# Data-pipeline + benchmark supply chain (D8). Runs the HERMETIC slice
# of the PyPSA-EUR pipeline suite (scripts/pypsa_eur) and the Codabench
# scorer parity guard (scripts/game_mode). These live outside
# pytest.ini's testpaths (expert_backend/tests), so they need an
# explicit path. Tests that require the uncommitted raw OSM CSVs skip
# gracefully (conftest osm_dir / regenerate_grid_layout guards), so the
# suite is green from a fresh clone. scripts/game_mode/test_score.py is
# pure stdlib and pins score.py to the shared golden fixture the
# frontend's scoring.test.ts also asserts — locking cross-language parity.
# ------------------------------------------------------------------
test-data-pipeline:
name: Data pipeline + scorer parity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: "3.10"
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ".[test]"
- name: Run pipeline + scorer + config-consistency tests (hermetic slice)
run: >-
pytest scripts/pypsa_eur scripts/game_mode
scripts/test_recommender_pin_consistency.py
scripts/test_extract_network_zip.py -q

test-frontend:
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -123,12 +153,11 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install ".[test]"
# Track the latest published expert_op4grid_recommender release: the
# >=0.2.4 floor documents the minimum the GST / superposition tests
# need, and pip + --no-cache-dir always resolve to the newest release
# above it (no stale pinned version to bump). --no-deps skips the
# recommender's heavy transitive stack (pypowsybl already comes from
# co_study4grid's own dependencies).
pip install --no-deps --no-cache-dir "expert_op4grid_recommender>=0.2.4"
# Pin expert_op4grid_recommender to the exact version in
# recommender-pin.txt (QW8) so an upstream release can't silently turn
# a green PR red; the weekly canary.yml floats to latest and flags
# regressions. --no-deps skips the recommender's heavy transitive
# stack (pypowsybl already comes from co_study4grid's own deps).
pip install --no-deps -r recommender-pin.txt
- name: Run graphviz-dependent Pytest subset
run: pytest expert_backend/tests/test_overflow_html_dim_logic.py
Loading
Loading