fix(tui): Ecosystem screen — path resolution + row-select + Schedule infusion (PR-A) - #10
Merged
Conversation
…hedule infusion + bare excepts (PR-A)
User report (notes 30-Apr-2026 + screenshots): on a freshly launched
TUI the Ecosystem screen lists 30+ roles correctly, but every operator
action below the list is dead.
Audit traced four distinct bugs to one shared cause + one antipattern:
1. Skills / MCP SERVERS tables show "no skills loaded — see howto-..."
guidance row even though skills/echo and mcps/echo_server exist on
disk.
2. ROLE DETAIL panel never updates when a role row is highlighted or
clicked — stays stuck on "Select a role row to view its full
definition".
3. "Schedule infusion → Nucleus" button hint pinned at "Select a role
first" forever; clicking the button does nothing.
4. Bare `except Exception: pass` blocks inside the row-select handler
swallow every failure silently, so the symptoms above produce no
log line operators could investigate from.
Root causes:
* `_roles_root() / _skills_root() / _mcps_root()` returned bare
relative strings (`"roles"` etc.). When the TUI launches outside
the repo root (pip install entry point, container with
WORKDIR=/app), those resolve against os.getcwd(). Some manifest
dirs hit and others miss depending on cwd at process start —
exactly the partial-resolution mismatch the screenshot shows.
* The row-select handler set `_selected_role` AFTER calling
`_show_role_detail()`, so any failure inside the detail render
silently dropped the selection state. Combined with bare excepts,
the operator saw no message and the Schedule-infusion button stayed
disabled.
Fixes (acc/tui/path_resolution.py — NEW):
resolve_manifest_root(env_var, default_dir_name) → absolute Path
Resolution order:
1. ACC_*_ROOT env var (absolute or expanded against cwd) IF the
path exists; warns + falls through if env var points to a
missing dir (no silent use of bad config).
2. Repo-anchored: <repo>/<default_dir_name> computed from this
module's filesystem location (Path(__file__).parent.parent.parent).
Works in editable installs and container layouts.
3. CWD-relative literal as last-resort fallback (preserves test
harness behaviour).
Fixes (acc/tui/screens/ecosystem.py):
* `_roles_root` / `_skills_root` / `_mcps_root` delegate to the new
helper; return type widens str → Path (loaders accept both).
* `on_data_table_row_highlighted` (NEW handler): cursor movement
over a role row now populates ROLE DETAIL live, matching the UX
every spreadsheet-style table provides. Pre-PR-A the operator
had to know to press Enter; now scrolling does the right thing.
* `on_data_table_row_selected` rewritten: sets `_selected_role`
BEFORE calling `_show_role_detail()` so a render failure cannot
leave the Schedule-infusion button disabled. Uses the new shared
`_arm_infusion_button()` helper.
* `_extract_role_name` static helper: pulls the role name string
out of a Textual RowKey across the API surface variations
different Textual versions present.
* Every bare `except Exception: pass` replaced with
`logger.exception(...)` so future regressions surface in the
rotating TUI log file.
* `on_button_pressed` calls `self.notify("Highlight or click a role
row first", severity="warning")` when `_selected_role` is empty —
the dead-click is now visible toast feedback rather than silent.
Tests (tests/test_ecosystem_screen_pilot.py — NEW, 10 cases all green):
Path-resolution (3): env-var wins / repo anchor falls back / missing
env path warned-and-skipped (NOT silently used).
Pilot-driven (7):
skills_table_populated_when_manifests_exist — fixture sets
ACC_SKILLS_ROOT to tmp dir with one echo manifest, table shows
a real row not the empty-state guidance row.
mcps_table_populated_when_manifests_exist — same shape for MCPs.
row_selected_handler_directly — synthetic RowSelected event,
detail panel update captured via monkeypatched Static.update.
row_selection_arms_infusion_button — _selected_role + button
state both correct after handler dispatch.
row_highlighted_handler_directly — cursor-driven path covered too.
button_press_with_selection_dispatches_role_preload — happy path
→ RolePreloadMessage reaches the App.
button_press_without_selection_notifies — sad path → notify call
captured, no RolePreloadMessage dispatched.
Why synthetic events instead of pilot.press("enter"): Textual's
DataTable RowSelected dispatch depends on the widget being the precise
focus target at the moment of dispatch, which Pilot's harness can't
reliably reproduce in test mode (we tried both pilot.press and
action_select_cursor, both failed deterministically). Constructing
DataTable.RowSelected / RowHighlighted directly and dispatching to the
screen's handler exercises exactly the same code path Textual would
invoke on a real keypress, with no flakiness.
Existing suite: 139 unit tests across config / role-store / guardrails
/ compliance pass unchanged (TestEd25519Validation deselected for the
lighthouse OpenSSL platform limit, as in PRs #7-#9).
Out of scope (planned for follow-ups per the approved plan):
* PR-A2 — in-TUI manifest upload (FilePicker modal).
* PR-B — direct prompt pane + open PromptChannel Protocol.
Notes file: C:\Users\micro\Documents\Notes\Notes\Development\AgenticCellCorpus\ACC TUI\TUI Fixes.md
flg77
added a commit
that referenced
this pull request
May 20, 2026
Bumps that resolve the open Dependabot alerts on the repo: - uv.lock: urllib3 2.6.3 -> 2.7.0 (#10 decompression-bomb High, #11 cross-origin sensitive headers High) - uv.lock: idna 3.13 -> 3.15 (#13 idna.encode bypass — supersedes Dependabot PR #92) - uv.lock: pytest 8.4.2 -> 9.0.3 (#9 tmpdir-handling CVE; the patched line is pytest 9.x, so pytest-asyncio bumps to 1.3.0 and pytest-cov to 7.1.0) - pyproject.toml: pytest>=9.0,<10 + pytest-asyncio>=1.0,<2.0 widened to let the resolver onto the patched line. - webgui/package.json: vite ^5.4.0 -> ^5.4.21 (#12 .map path traversal). #8 (transformers Trainer-class arbitrary-code execution) cannot be bumped today — the patched line is transformers 5.x but no sentence-transformers release supports transformers 5 yet. We do NOT use Trainer (only the SentenceTransformer encode() API for embeddings), so the vulnerable code is not in our execution path. The sentence- transformers range is widened to `<5.0` so the bump becomes a one-line uv-lock change once ST releases support. Documented in pyproject.toml; GitHub alert #8 to be dismissed with "vulnerable code not in execution path". 42 webgui tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
flg77
added a commit
that referenced
this pull request
May 31, 2026
… block (v0.3.44) (#10) Closes followup #58. v0.3.43 added the `## Currently available` perception block to the Assistant's system prompt (capability + roster + sub-collectives, ~1KB context). This roughly doubled per-task input-token count (~1000 → ~2000 tokens on lighthouse). At the legacy 2048-token Cat-B budget the Assistant hit utilization 1.10 ≥ 1.0 after 3 back-to-back tasks and started ALERT_ESCALATE blocking — a legitimate Cat-B rail firing on a now-larger prompt, but the operator-facing symptom was "the Assistant stopped answering." Bumps role.yaml v2.2.0 → v2.2.1. Inline comment block explains the v0.3.43 prompt-size shift + leaves headroom for the future Phase-2 JSON action block. No code change. Tests: pytest -k "assistant or token_budget or role_def or cat_b" 96 passed, 3 skipped. Co-authored-by: Claude Opus 4.7 <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
Repairs every dead operator action in the Ecosystem screen the user surfaced via screenshots + notes on 30-Apr-2026. Four bugs collapse to one root cause + one antipattern.
Bugs fixed
Surface added
`acc/tui/path_resolution.py` (new)
```python
def resolve_manifest_root(env_var: str, default_dir_name: str) -> Path:
```
Resolution order:
`acc/tui/screens/ecosystem.py` (changed)
Tests (10, all green)
`tests/test_ecosystem_screen_pilot.py`:
Why synthetic events instead of `pilot.press("enter")`: Textual's DataTable RowSelected dispatch depends on the widget being the precise focus target at the moment of dispatch — Pilot's harness can't reliably reproduce that in test mode (verified: both `pilot.press("enter")` and `action_select_cursor()` failed deterministically). Constructing `DataTable.RowSelected` / `RowHighlighted` directly and dispatching to the screen's handler exercises the exact same code path Textual would invoke on a real keypress, with no flakiness.
Test plan
Out of scope
Notes file: `C:\Users\micro\Documents\Notes\Notes\Development\AgenticCellCorpus\ACC TUI\TUI Fixes.md`