feat(dashboard): surface evolution-engine state (reward hacking, seesaw, variants, landscape, manifests)#80
Merged
Merged
Conversation
…igest, AdaptationLandscape, SolvedTaskRegistry, SkillVariant) Wire struct fields into existing initializers so the dead-code type definitions compile. No behavior change yet — these are the substrate for the P1 evolution-gap implementation (R1-R7). Refs: gap-analysis ref-010-harnessx-gap-analysis
Add edit_type column to evolution_records schema with idempotent ALTER TABLE migration (ensure_column via pragma_table_info). Wire EditType::as_str()/from_db_str() through INSERT/SELECT so the field round-trips instead of being hardcoded to AddSkill. Refs: gap-analysis ref-010 §3.3, Quick Win #1
New src/evolve/digester.rs compresses a session's ObsRecord stream into per-task TaskDigest summaries: outcome (success/partial/complete-failure), ranked failure categories, implicated logical components (file->module), curated evidence excerpts (max 3), tool trajectory, token estimate, and cross-iteration persistence counter. Segmentation: pipeline_id grouping first, then 5-min idle-gap splitting, falling back to whole-session. Pure-function core, fully unit-tested (9 tests). Refs: gap-analysis ref-010 §3.1 (HarnessX paper §4.3 Digester)
New src/evolve/planner.rs builds AdaptationLandscape from evolution history + current digests: persistent failures (>=N sessions), attempted edits, edit-type coverage, untried edit types, component failure heatmap. recommends_exploration() flags under-exploration (HarnessX §4.2 pathology): unresolved persistent failure + untried structural edit types. This is the signal the proposal builder will use to inject exploration beyond local repair. Pure-function core, fully unit-tested (8 tests). Refs: gap-analysis ref-010 §3.2 (HarnessX paper §4.3 Planner)
New src/evolve/edits.rs defines HarnessEdit as an enum (not trait object, per architecture review — cheaper clone for forking, exhaustive match for the variant gate). Five variants: AddSkill, ModifySkill, AddInstinct, ModifyConfig, AddGuardRule. Each carries a falsifiable EditManifest (HarnessX Table 9): edit_type, target, intended_effect, predicted_impact. AddSkill/ModifySkill are concrete (delegate to existing writers); the structural variants report NotImplemented but exist so the Planner's edit-type coverage analysis sees the full taxonomy. validate() guards name safety + non-empty content. append_tuning_section_pub exposes the existing private editor. 7 unit tests. Refs: gap-analysis ref-010 §3.3 (HarnessX paper §4.3 Evolver)
New src/evolve/seesaw.rs implements the HarnessX seesaw constraint (§4.1): reject any edit that regresses a previously solved task below its best score minus tolerance. CRITIC FIX: the original scaffolding tracked per-(task,dimension) scores. The paper (§6.6, §7.6) proves per-dimension gating fails on sub-threshold coupling. Redesigned to per-task (single best outcome score per task_id), matching the paper's intent. This is a deliberately coarse gross-regression gate; variant isolation (R6) is the real catastrophic-forgetting defense. - SolvedTaskRegistry redesigned (TaskDimensionKey removed) - scores_from_digests maps digests to per-task success fractions - persisted to project_seesaw_path (seesaw.json) - 7 unit tests Refs: gap-analysis ref-010 §3.4 + Critic correction
New src/evolve/variants.rs implements HarnessX variant isolation (§4.5): maintain up to MAX_VARIANTS skill variants and route each task to the variant with the highest estimated success rate on its cluster. - route(): warm path uses observed success rate (>=4 samples), cold path falls back to stack-tag matching, then highest avg_score - fork_if_needed(): fork-on-regression — when an edit would regress another variant, spawn a sibling instead of rejecting; retires lowest-scoring variant when pool full (separate from MAX_EVOLVED_SKILLS, per arch review) - detect_stack(): heuristic stack detection from task context (Critic: no stable cluster definition exists without a benchmark, so cold-start is stack-based and warms to observed success) - per-variant routing stats accumulate for warm routing 9 unit tests. Depends on R4 typed edits (paper §7.1: isolation ill-posed without explicit edit scope). Refs: gap-analysis ref-010 §3.5 (HarnessX paper §4.5, §6.3)
Integrate the new P1 modules into the reflect evolution loop (src/hooks/reflect.rs) per the Architect's integration map (analyze -> digest -> build_proposals -> curate -> gate+seesaw -> variants -> write): - After analyze_session(): run digest_session() to build per-task digests; populate SessionAnalysis.persistent_failure[_categories] from them - Build AdaptationLandscape from history + digests; emit an exploration hint when recommends_exploration() (unresolved persistent failure + untried structural edit types) - After seeding: check the seesaw registry; if digests regress a solved task, skip further seeding and warn; update the registry with this round - Clean up 4 clippy warnings (derive Default, rename from_str, drop redundant cast/map_or) No behavior change for sessions without regressions. 602 lib tests green, clippy clean. Refs: gap-analysis ref-010 §3, Phase 1 integration
CI runs 'cargo clippy -- -D warnings' across all targets, which is stricter than the lib-only check run locally during Go phase. The R4 (HarnessEdit) and R6 (VariantPool) APIs plus the P2/P3-reserved types (HarnessDimension, HarnessSnapshot, ConfigSummary, MetricsSummary, SkillVariant) are not yet invoked from the bin targets, so dead_code warnings became errors. - Add #![allow(dead_code)] to edits.rs, variants.rs (APIs reserved for the next wiring step; planner coverage analysis needs the full taxonomy) - Add #[allow(dead_code)] to reserved evolution.rs types (P2 first-class object, P3 dimension tags) - Use seesaw::DEFAULT_TOLERANCE in reflect.rs instead of a hardcoded 0.1 so the constant is live - Drop unused re-exports (HarnessEdit, VariantPool, detect_stack) from evolve::mod — the modules stay pub-accessible by path
Compute Metrics.reward_hacking_suspected via least-squares slope over the last reward_hacking_window sessions: reward hacking = output_quality slope falling while execution_cost (efficiency proxy, higher=better) slope rising. - config: reward_hacking_window(5)/quality_drop(0.05)/cost_rise(0.05) - src/evolve/metrics.rs: detect_reward_hacking() + series_slope() NaN guard - src/store/metrics.rs: persist reward_hacking_suspected + epoch_class via metrics_state key/value (true round-trip, was hardcoded) - src/hooks/reflect.rs: set flag after classify_epoch, before save - 10 unit tests + config/store assertions Pairs with Tier 2.1 Critic (seesaw without reward-hacking defense is exploitable per paper §4.3). Flag-only here; seeding suppression is the Critic's job. Refs: gap-analysis ref-010 §4.2
Hermetic integration tests for the evolution engine — no live benchmark, no SQLite, no network, no HOME redirect. Fixtures embedded via include_str!. 6 scenarios, each with a negative control so it can't be vacuously true: - seesaw catches regression (PIPE-1 1.0 -> 0.25) - variant forks on regression (locks fork contract before R6 wiring) - planner recommends exploration (persistent failure + untried types) - outcome_score bounds + divide-by-zero guard - task-identity-is-pipeline-stable (hermeticity guard) - edit-coverage marks attempted vs untried types This is the validation substrate the Council (Critic/Pragmatist/Skeptic) demanded before the R4/R6/R5 wiring claims can be trusted. Refs: gap-analysis ref-010, Critic/Skeptic concern: 'no benchmark'
R4 (typed edits): split seed_smart_skills() into plan_skill_edits() (pure planner, emits Vec<HarnessEdit>) + apply_skill_edits() (executor via HarnessEdit::apply/validate) + a thin wrapper preserving the exact ->u64 signature and hint ordering. 602+ tests unaffected. R5 (seesaw auto-reject): reordered to check BEFORE seeding (digests were already available from step 2b), so a regressing round blocks NEW skill commits at the source instead of warning after the fact. Also fixes a latent bug: reg.update() now only runs when the gate passed (monotonic update could otherwise raise best-of on coincidental high scores, masking future regressions). R6 (variant isolation): VariantPool gains load()/save() (atomic tmp+rename, graceful corrupt-file reset). reflect records the session's dominant stack outcome and forks-on-regression when seesaw blocks. MAX_VARIANTS stays separate from MAX_EVOLVED_SKILLS. Cold/empty pool degrades to no-op. 613 lib tests + 6 regression harness tests green, clippy --all-targets -D warnings clean, fmt clean. Refs: gap-analysis ref-010 §3.3/§3.4/§3.5
Defends against reward hacking (paper §4.3). epic-harness forbids external LLM calls from production, so the in-loop Critic is deterministic: - src/evolve/critic.rs: Critic::should_block_seeding(metrics) — the earlier, coarser gate pairing with seesaw. verify_against_evidence() rejects manifests claiming a score lift when reward hacking is suspected. - src/hooks/reflect.rs: critic_block computed pre-seed (probes score_history with this session's dimensions), suppresses seeding + short-circuits seesaw hint duplication. - registry/skills/_critic/SKILL.md: the out-of-band LLM counterpart for non-local effects the deterministic check cannot catch. Ships WITH Tier 2.2 (the Critic warning: seesaw without reward-hacking defense is exploitable). 5 critic unit tests. Refs: gap-analysis ref-010 §4.1
Wires the HarnessX Table 9 falsifiability contract end-to-end:
- apply_skill_edits now Critic-verifies each edit's manifest BEFORE apply;
Reject verdicts skip the edit (defense-in-depth beyond the round-level
reward-hacking block). Returns ApplyOutcome { applied, manifests }.
- seed_smart_skills takes &Metrics and returns ApplyOutcome so reflect can
persist the manifests.
- reflect appends each shipped manifest to a sidecar manifests.jsonl the
next round's Critic reads to verify predictions held; EvolutionRecord
gains a #[serde(default)] manifests field (backward-compatible).
- EditManifest + Metrics now derive Serialize/Deserialize/Default.
- AddSkill manifest predicted_impact now references avg_score_with so the
Critic's score-lift contradiction check can fire.
- 2 new unit tests (apply emits manifest; Critic reject skips edit + no
manifest + no skill written).
Critic verify_against_evidence is now live (was allow(dead_code)).
Refs: gap-analysis residual A, paper §4.3 Table 9
HarnessEdit::AddGuardRule now applies: appends a blocked/warned rule to the project guard-rules.yaml via a new append_guard_rule() helper in guard.rs. - Read-modify-write (no clobber of existing rules), atomic write (tmp+rename), round-trip safe through the incumbent parse_guard_rules parser - validate() rejects empty/pathologically-long patterns (GUARD_PATTERN_MAX_LEN) - ModifyConfig/AddInstinct stay NotImplemented (reserved for coverage) - 9 tests (5 guard round-trip/atomic, 4 edits validate+apply) Planner auto-emission is intentionally NOT wired yet (conservative — the editor is concrete so a follow-up can emit it). Makes the Planner's 'add_guard_rule' untried_edit_type attemptable. Refs: gap-analysis residual B
…2.3) HarnessSnapshot is now constructed (was allow(dead_code)) and exposed via a read-only CLI: 'epic harness snapshot' (JSON), 'epic harness diff <a> <b>'. Restore deferred (destructive). - src/evolve/snapshot.rs: build_snapshot() aggregates config + skills + guard rules + metrics + deterministic content hash (canonical sorted-keys JSON) - src/harness_cli.rs: snapshot/diff/restore dispatch following the repo's non-clap run(&args) pattern - diff_snapshots: recursive structural diff (objects leaf-by-leaf, arrays as sets), timestamp-excluded - 17 tests (10 snapshot, 7 CLI) Refs: gap-analysis residual C/P2.3
…C/P3) Formalizes the existing evolution engine as an RL analogy (paper §4.1-4.2, §7.3 'design checklist not predictive theory'). Maps state/action/reward + the three pathologies (reward hacking, forgetting, under-exploration) to their concrete epic-harness defenses with code locations + a tuning guide. Adds 'dimension:' frontmatter to 6 core static skills (tdd/secure=control_ and_safety, verify/perf=evaluation_and_reward, debug=observability, simplify=context_assembly) enabling future dimension-scoped analysis. Processor trait (P3.3) deliberately deferred — most invasive, gated on P1/P2 validation. Refs: gap-analysis residual C/P3
Adversarial code review confirmed: manifests are WRITTEN (reflect persists to EvolutionRecord + manifests.jsonl) but the Critic that READS them to verify prior predictions held is not yet wired — today's Critic only consults the in-round reward-hacking flag. The doc comments claimed a closed falsifiability loop, overstating residual A. Corrected 4 doc sites (paths.rs, evolution.rs, edits.rs, skills.rs) to state the honest status: write-path wired, read-path (cross-round falsifiability) is a deferred follow-up. No code change — the behavior was always correct; only the framing was overclaimed. The per-edit Critic gate is now documented as defense-in-depth that cannot diverge from the round-level gate today (both key off reward_hacking_suspected), with the manifests_file evidence vector as the intended future extension.
Adds a typed Processor trait over the existing CLI-subcommand hooks, the foundation HarnessX's paper §3.2 describes, adapted to epic-harness's out-of-process model. - HookPoint enum maps the 6 lifecycle points epic-harness uses (SessionStart, PreToolUse, PostToolUse, PostEdit, PreCompact, SessionEnd) to their subcommand names, round-trippable via from_subcmd - Processor trait (hook_point/profile/process) + 6 concrete processors that delegate UNCHANGED to the existing run(&HookInput) -> i32 fns - all_processors() static dispatch table enumerates the wiring (introspectable by HarnessSnapshot / future tooling) - dispatch() typed entry point Representational only — NO behavior change. This honors the Architect's red flag (in-process event-pipeline redesign would be the single most invasive change) while establishing the seam typed edits / variant isolation can later attach metadata to. 5 unit tests. Also fixes a pre-existing flaky test (rebuild_produces_stable_hash) found under multi-threaded runs: it called live build_snapshot() twice and could diverge when a parallel test wrote to evolved_dir(). Switched to the hermetic make_fixture_snapshot helper. Refs: gap-analysis residual P3.3 (final item)
…aw, variants, landscape, manifests) The 4-PR evolution stack wrote backend state the dashboard couldn't see. This wires the read path: serve.rs — new handle_harness_cmd arms: - get_seesaw_registry (reads seesaw.json via load_registry) - get_variant_pool (reads variants.json via VariantPool::load) - get_harness_snapshot (build_snapshot — first-class object) - get_adaptation_landscape (Planner output: persistent_failures, edit_type_coverage, untried_edit_types, component heatmap) - get_manifests (tail-reads manifests.jsonl falsifiability ledger, capped 50) - get_session_snapshots / get_global_patterns / get_effect_pending (previously broken — returned 'null' via fallthrough; now implemented) harness.ts — client wrappers + types (SolvedTaskRegistry, VariantPool, HarnessSnapshotData, AdaptationLandscape, EditManifestEntry; HarnessMetrics gains reward_hacking_suspected + epoch_class). Evolution.svelte — reward-hacking warning banner (when reward_hacking_suspected), Seesaw/Variants/Adaptation-landscape panels, edit_type column in evolution history. Parallel best-effort fetch (Promise.allSettled) so a cold project degrades gracefully. assets/dashboard.html rebuilt (vite build; my Evolution.svelte is type-clean; pre-existing i18n-key errors in Memory/Settings are unchanged and don't block vite build). 643 lib tests green, clippy --all-targets -D warnings clean. Refs: gap-analysis ref-010 dashboard-surfacing audit
…cing Final release-docs commit for the 5-PR HarnessX stack (#75–#80). CHANGELOG.md — [0.7.0] entry covering: Digester, Planner, typed edits, seesaw, variant isolation, reward-hacking detection, Critic, falsifiability ledger, AddGuardRule editor, regression harness, Processor abstraction, HarnessSnapshot/CLI, dashboard surfacing (5 handlers + 3 fixed panels + Evolution.svelte panels/banner), operational-mirror doc + dimension tags, plus the seesaw reg.update() latent-bug fix and SQLite migrations. Known limitations documented. README.md — new 'HarnessX-Inspired Defenses (v0.7.0)' table (8 defenses → module → pathology → paper §), 'Harness Snapshot (v0.7.0)' CLI section, and dashboard blurb updated to mention the evolution-engine surfaces. Version bump 0.6.5 -> 0.7.0 synced across all 6 files (Cargo.toml, package.json, app/package.json, .claude-plugin, .codex-plugin, gemini-extension.json) + assets/dashboard.html rebuilt with the new fallback version. 643 lib tests green, clippy --all-targets -D warnings clean.
When a polled section's data changes between refreshes, its border glows blue for ~1.6s (hx-flash-glow keyframe in app.css) so the eye is drawn to freshly-updated panels. Applied to 4 polling pages: - Evolution: reward-hacking banner + seesaw/variants/adaptation-landscape panels - Dashboard: key-metrics grid + tool-stats panel - OrbitPipeline: running-pipeline cards - Agents: agent cards (status signal only — not every 5s poll) Each page's flashIfChanged() compares a CANONICAL (sorted-key) JSON signature of the payload against the previous poll. Canonicalization is essential: the adaptation-landscape handler recomputes build_landscape() each call, and its HashMap-backed fields (edit_type_coverage, component_failure_heatmap) iterate in non-deterministic order, so plain JSON.stringify produced a different signature every poll (constant false-positive flashing). canon() sorts object keys recursively so only real data changes trigger the glow. assets/dashboard.html rebuilt.
The project dropdown in the Topbar was permanently empty and pinned to
the last-selected project, with no way to switch projects or see the
cross-project aggregate. Root cause: the frontend calls loadProjects()
-> fetch('/api/projects') on mount, but no such route existed in
serve.rs — every poll returned 404, so the dropdown stayed empty and
localStorage's last value (a single project) remained selected. Because
the UI looked fine, prior fixes only touched the Svelte layer and the
problem kept recurring: the data source had never been implemented.
This adds the missing backend support and makes project selection
actually filter data:
1. GET /api/projects — enumerates ~/.harness/projects/* slugs (sorted),
feeding the dropdown. The '__all__' option is a frontend default.
2. /api/harness now reads the ?project= query param and threads it into
handle_harness_cmd. Absent or '__all__' -> None (cross-project).
3. load_metrics_scoped_pool(project) — new metrics loader scoped to a
project slug or aggregated across all. The old load_metrics_pool ran
'WHERE key = ?' with fetch_optional against a (key, project)-keyed
table, returning indeterminate rows once multiple projects had
written. Aggregates now SUM/weight-avg with CAST(value AS REAL)
(the column is TEXT, so implicit numeric math silently yielded 0)
and decode as f64 (REAL results don't decode into i64).
4. query_obs_stats_scoped_pool(project) — same treatment for
observations: static-SQL two-branch form (sqlx 0.9 SqlSafeStr rejects
dynamic strings) so each query adds 'AND project = ?' when scoped.
Verified live: __all__ shows sessions=885 / 101k obs across 94 tools;
epic-harness shows 118 sessions / 15.8k obs / 41 tools; alcove shows 36
sessions. Switching projects now returns genuinely different data.
The Agents page rendered only the skeleton and never finished loading.
A console error fired on every render of the run-summary stat grid:
TypeError: r(...)(...) is not a function
The offending template was {$tStore('ofAgents')(run.agents.length)}.
tStore returns translate() — a STRING, not a function — so calling the
result with (n) threw. The parametrized key ofAgents exists in en.ts as
(n) => 'of N agents', but it is consumed via the variadic args of
tStore: tStore(key, ...args). The double-call form was a copy-paste bug.
Fixed to tStore('ofAgents', run.agents.length). No other double-call
sites exist (grep across app/src). Verified via Playwright: skeletons 0,
42 agent cards render, 'of 42 agents' shown, zero console errors.
… skills A prior commit (c35c17c, 5/29) renamed the dashboard's Ring 1 from 'Commands' to 'Pipeline' across sidebar, page header, dashboard ring card, and i18n. Subsequent work dropped those changes (git blame on Sidebar.svelte's Ring 1 label points back to 6dfcf33, 5/18 — the rename was silently reverted), so the UI showed 'Commands' again. The user reported this as a version regression. Restored the rename AND expanded the Pipeline page from 3 entries (orbit/evolve/team) to all 9 Ring 1 pipeline skills in spec->ship order: discover, spec, go, audit, eval, ship, orbit, evolve, team. Changes: - Sidebar: 'Ring 1 · Commands'/'Commands' badge 3 -> 'Ring 1 · Pipeline'/'Pipeline' badge 9 - Commands.svelte: 9 pipeline skill cards; subtitle 'Ring 1 · Skills' - Dashboard 4-Ring card already showed Pipeline (no change needed) - en.ts + ko.ts: pageCommands -> Pipeline, pageCommandsDesc3 -> 9-skill copy, added cmdDiscover/Spec/Go/Audit/Eval/ShipDesc, ring1Desc -> '9 pipeline skills' - de/es/fr/hi/ja/pt-BR/zh-CN/zh-TW: pageCommands localized to Pipeline equivalent Verified via Playwright on /commands: header 'Pipeline Ring 1 · Skills', 9 cards render (/discover ... /team), sidebar shows 'Ring 1 · Pipeline', zero console errors.
Redesigned the Pipeline (Ring 1) page so the spec->ship flow is visible as an actual diagram, mirroring the epiccounty.com/ecosystem visual language (central node + satellite nodes connected by labelled flow lines) instead of a flat card grid. - Central /orbit orchestrator node (highlighted, double-boxed) sits in the middle with 'ORCHESTRATOR / spec -> ship auto' - 6 phase nodes (discover/spec/go/audit/eval/ship) orbit it, connected by dashed flow lines with numbered badges 1-6 and arrowheads - Clicking any node copies the /command - Cross-cutting orchestrators (evolve, team) grouped below in a separate panel with purple accent The geometry is computed in-script (6 satellites evenly spaced on a circle of radius 175 around (360,245) in a 720x490 viewBox). All SVG nodes are focusable buttons for keyboard access. Verified via Playwright: 1 orbit node + 6 phase nodes + 6 numbered flow lines render at 720x490, evolve/team in cross-cutting grid, zero console errors.
Replaced the circular phase diagram with the /orbit decision flow that matches the README mermaid chart — a top-down branching tree showing the full spec->ship lifecycle, not just the phase names. The SVG renders the complete orbit state machine: - /orbit (start) -> requirement? (decision) - unclear -> Interactive (/discover -> /spec, then 'orbit go') - complex -> Council (4-voice auto-spec) - simple -> Direct (auto-spec) - -> Load spec (merge) -> Go (plan -> TDD -> integrate) -> Check - Check --PASS/WARN--> Ship ; --FAIL--> retry<3? - yes -> loop back to Go ; no -> Pause - Pause --abort--> Abort ; continue -> Go - Ship -> Evolve (auto-analyze session) Node colours follow the README classDef: purple (#4a4a6a) for human checkpoints (Interactive, Pause), green (#1a5c3a) for autonomous steps (Council/Direct/Go/Check/Ship/Evolve), dark blue diamond for the mode decision, brown for the merge + retry gate. Edges carry the same labels as the README (unclear/clear+complex/simple, PASS/WARN, FAIL, yes/no, abort). Go/Check/Ship/Evolve/orbit nodes are clickable to copy the command; evolve/team listed separately as cross-cutting orchestrators. Verified via Playwright: 11 nodes + 15 labelled edges render at 620x760, all decision labels present, zero JS console errors.
The agent card grid was rendering all 42 agents from the run, most of
which completed days ago. Older agents are already available in the
completed table below, so the cards now show only:
- agents currently running, OR
- agents completed within the last 24h (by completed_at, falling back to
started_at when completed_at is absent)
Agents outside that window are excluded from the cards, and a hint
('+N older agents — see completed table below') makes clear where they
went. When nothing is recent, an empty-state note appears instead of a
blank grid.
Verified via Playwright: card count dropped from 42 to 1 (only the agent
that ran ~1h ago), '+41 older agents' hint shown, completed table still
lists the full history.
Switching the project dropdown didn't refresh the Evolution page or the Agents obs table — they loaded once on mount and polled on a timer, never re-reading selectedProject. The backend already returned project-scoped data, but the pages never asked for it again, so every project showed the same numbers (looked like the project filter had regressed). Frontend: replaced onMount-only load in Evolution.svelte and Agents.svelte with a $effect that depends on $selectedProject, so changing the dropdown re-runs load() (and re-arms the poll interval). Matches the pattern Dashboard.svelte and Memory.svelte already use. Removed the now-unused onMount imports. Backend: get_evolved_skills was ignoring the project param entirely — it called list_skills_full_pool / query_recent_records_pool / load_metrics_pool, all unfiltered, so it always returned the global recent-50 history regardless of selection. Added project-scoped variants: - evolved::list_skills_full_scoped_pool(project) - evolution::query_recent_records_scoped_pool(limit, project) - metrics::load_metrics_scoped_pool(project) (already existed) and wired get_evolved_skills to use them. Static-SQL two-branch form for sqlx 0.9 SqlSafeStr. Verified via Playwright on /evolution: switching epic-harness -> alcove -> __all__ now changes Sessions Analyzed (7 / 0 / 11) and the history table, and the network tab confirms all 5 harness API calls re-fire with the new project= query param on each switch.
This was referenced Jun 18, 2026
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
Stacked on #79. Wires the dashboard read-path to the 4-PR evolution stack's backend state. Previously these features were computed/persisted but invisible in the UI.
Changes
Check
Test Plan
Note
Pre-existing i18n-key errors in Memory/Settings.svelte (29) are NOT fixed here (out of scope); they don't block vite build.