Repository navigation
feat(dashboard): a live, read-only dashboard: scio dashboard (#68) - #70
Merged
Merged
Conversation
scio/dashboard/contract.py fixes what every layer speaks before any layer is built: the response models (Workspace, ThreadSummary, StopInfo, ThreadDetail, GraphDiagram, ThreadVersion, ChangeEvent) and the DataSource protocol. The fixtures in tests/fixtures/dashboard/ come from a real Fake build's checkpoints and validate against the models; tests/dashboard_support.py serves them as a DataSource for the API and page tests. The `dashboard` extra adds FastAPI and uvicorn; the core install is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lds (wave 0, #68) A stop arrives as a pending write on a checkpoint that already exists, so a version built from the checkpoint id alone never showed a thread starting to wait: ThreadVersion counts the thread's writes too. A crash leaves a pending __error__ write (seen read-only on the live graphcalc DB), now status `crashed` with the error text. A build is recognised by `product_dir` as well as `feature_runs`, so one that stopped before its first feature still counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the contract (wave 0, #68) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…68) - scio/dashboard/data.py: CheckpointDataSource reads each root's checkpoint DB read-only (mode=ro, SqliteSaver.setup skipped, a connection per call), classifies threads by their channels, reuses the scio report builders, and reads stops, crashes, progress.json and feature-thread links. - scio/dashboard/app.py: create_app serves the contract's GET routes and a /ws WebSocket that polls versions and pushes changes; Host and Origin are checked so only the loopback page can read it; a test asserts every route is a read. - scio dashboard [--root DIR ...] [--port 8765] binds 127.0.0.1 only. - CostLedger.load_entries keeps only complete lines, so scio report no longer dies on a live run's half-written last line (I-127); transcripts are read with errors="replace". - An AST scan guards the LF rule for every text write (I-126). - ADR 0017, docs/OBSERVABILITY.md, README, CHANGELOG, PRODUCT_MODE; ledger I-120 to I-128, guardrails 20 to 25. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… views (wave 1, #68) Plain HTML/CSS/JS with no build step. The threads list is grouped by root and product, with waiting, crashed and error rows. The build view lights the current step on the milestone graph and shows feature runs, integration lines, the PR, the timeline and SVG cost bars; the feature and bootstrap views follow the same shape. Live refresh over /ws with reconnect and backoff. Mermaid 11.15.0 from cdnjs with SRI, falling back to text; a CSP allows only self and cdnjs scripts. DOM is built with textContent only. Playwright tests run against a fixture server with a stub Mermaid, offline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, cost, running_usd (wave 2, #68) SCIO appends a FeatureRun only when an attempt ends, so on the live graphcalc build the feature running now read "not run" and its spend was missing from the build's costs. The contract now names the build's feature threads without a run as running, counts their spend in cost_by_role and cost_by_feature, and carries it separately as running_usd; summary.usd stays the figure scio report prints. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… stop (wave 2, #68) - A build's feature threads with no FeatureRun yet are linked (running, or their own waiting/crashed/halted status) and their spend counts in the cost by role and by feature and as running_usd; the headline stays scio report's figure. Found on the live graphcalc build, whose P4 waits at advisor_cap. - scio dashboard bounds uvicorn's graceful shutdown: on Windows a reset connection kept asyncio.Server.wait_closed open forever, through a second Ctrl+C too (I-132). The real app serving the real page under uvicorn is now a test, which also stops it with a tab open and one closed (I-130). - The fixture source is thread-safe; ledger I-129 to I-132, guardrails 26 to 28, the dashboard retrospective. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t in the README (#68) The screenshot is the real graphcalc build seen through scio dashboard: P4's second attempt running, its spend in the cost bars, the human's retry in the timeline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ve spend, origins (#68) A fresh-context review of the whole diff, each finding confirmed by a probe: - an answered stop read "waiting" until its node returned; a __resume__ write beside the __interrupt__ now means answered (I-134), exact because no SCIO node interrupts twice, which a scan test keeps true - a resumed crash reads "crashed" until the resumed node returns; the DB has no signal, so the contract, ADR and docs say so (I-133) - one unreadable root made /api/threads a 500 for every root; it is skipped and logged, and answers 503 on its own (I-135) - next_nodes include pending Send packets, so T2's explorers light (I-136) - a running attempt's spend comes from its ledger, not its last checkpoint (I-137) - /ws accepts only the server's own origin; every response denies framing (I-138) Ledger I-133 to I-138, guardrails 29 to 33, the retrospective. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ral (I-139, #68) The M6 toolchain boundary scan keeps stack command words inside scio/toolchain/; the full suite caught the literal the wave gate's dashboard-only run did not. Ledger I-139, guardrail 34. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…68) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NewMe505
marked this pull request as ready for review
October 28, 2026 06:04
NewMe505
added a commit
that referenced
this pull request
Oct 30, 2026
Conflicts in the shared files, resolved by keeping both sides: the CHANGELOG's Fixed entries, the README status line (the dashboard is merged now), the ledger (I-114 to I-118, then I-120 to I-139), the guardrails (rule 17 merges I-117 and I-131; 20 to 34 are the dashboard's, 35 to 38 this branch's), and two appended build tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
scio dashboard [--root DIR ...] [--port 8765]is a live web view of SCIO's own state machine across workspaces, on 127.0.0.1 only. It shows:It never writes. It reads the checkpoint DB through
mode=roconnections, plus the cost ledgers andprogress.json, and reusesscio report's builders, so its costs equalscio report's. The page is plain HTML/JS with no build step, refreshed over a WebSocket. It ships as the optionaldashboardextra (FastAPI, uvicorn).docs/OBSERVABILITY.mdputs it beside the other two views: GitHub (--gh) and an OpenTelemetry trace viewer.Closes #68
The real
build-graphcalc-m1while it runs:featureis lit, P1 to P3 passed, P4's first attempt failed atadvisor_cap, and the second attempt is running at $1.93 (+ $1.9269 running), with the human's retry in the timeline.Plan vs. done
scio/dashboard/contract.py. Two probes came first (amode=roconnection underSqliteSaveron a WAL DB; a Fake build's channels and pending writes). Reviewing the contract against them caught I-120 before fan-out.CheckpointDataSource:mode=ro,setup()skipped, a connection per call; channel classification; stops, crashes,Sendpackets; feature links; tolerant ledger reads. 19 tests on Fake-build checkpoints, including a byte-identical DB after every read.create_app: GET routes only (a test asserts it),/wspolling versions, Host check, same-origin WebSocket, no framing. 54 tests.textContentonly. 13 Playwright tests, offline.scio dashboard, live check, shared docsLive check (graphcalc-run, while its build runs)
scio reporton a backup-API snapshot of the live DB: $9.0983 total, features $8.9244, orchestrator $0.1739, and every feature row and role identical./wspushedchanged: [build-graphcalc-m1-p4-a2], and the page fetched the list and the open build again, with no reload and no page errors.test_the_data_layer_never_writeshashes the main DB before and after every public method, and a write through the dashboard's connection raises. The ADR notes that amode=roreader on a DB with no open writer leaves empty-wal/-shmsidecars, which SQLite's next writer cleans up.waiting, though the build's last checkpoint was 26 minutes older than the stop (I-120 in practice).Test evidence
CI on
79dacc2:checks495 passed, 5 skipped (12m53s; the dashboard and Playwright tests ran);docker-livepass (1m1s).273246dadds only the CHANGELOG### Fixedline for I-127.The new tests:
tests/unit/test_dashboard_data.py: 19 tests on Fake-build checkpoints plus tiny graphs for a stop, its answer, a crash,Sendand unreadable rows.tests/unit/test_dashboard_app.py: 54 tests.tests/unit/test_dashboard_contract.py: the fixtures, and the one-interrupt-per-node scan.tests/unit/test_dashboard_cli.py: loopback only, bounded stop, the install hint.tests/live/test_dashboard_page.py: 13 Playwright tests.tests/live/test_dashboard_server.py: the real app and page under uvicorn, with a clean stop.tests/unit/test_lf_writes.py.test_m5_observability.py.Docs updated
[Unreleased]Continuous improvement
checkpoint_id\|get_state((I-120)uv sync --extra(I-124)write_text(\|open((I-126)load_entries(\|read_text(encoding="utf-8")(I-127)websocket_connect((I-128)wait_for_function(I-129)uvicorn\.\|serve_forever\|HTTPServer((I-132)__interrupt__(I-134)branch:to:(I-136)docs/LESSONS_LEARNED.md, "The dashboard". Guardrails 20 to 34 each name a guard; new scans:test_lf_writes.py,test_every_node_interrupts_at_most_once.Shared code fixed along the way:
CostLedger.load_entrieskeeps only complete lines, soscio reportno longer dies on a live run's half-written ledger line (I-127; the test fails on the old code)._read_artifactreplaces a broken character instead of raising.Risk notes
dashboardextra only;uv.lockupdated. The core install is unchanged, andscio dashboardwithout the extra says how to install it (--all-extras, never a bare--extra, I-124).crasheduntil the resumed node returns (I-133);in_progress, and only "last update" shows it.scio dashboard.Bottleneck audit
tests/live/test_dashboard_server.py::_Serverruns uvicorn as the CLI does.Agent run log
Not a SCIO agent PR: built by Claude Code sessions (an orchestrator, four wave agents and a review agent).
🤖 Generated with Claude Code