Skip to content

test(coding_agent): Pilot tests for the demonstrator role TUI flow (Tier B) - #22

Merged
flg77 merged 1 commit into
mainfrom
feat/coding-agent-tier-b-pilot-tests
May 1, 2026
Merged

test(coding_agent): Pilot tests for the demonstrator role TUI flow (Tier B)#22
flg77 merged 1 commit into
mainfrom
feat/coding-agent-tier-b-pilot-tests

Conversation

@flg77

@flg77 flg77 commented May 1, 2026

Copy link
Copy Markdown
Owner

Summary

Tier B of the coding_agent test plan. Tier A — schema invariants — landed in #21. This PR verifies the canonical TUI surfaces consume the coding_agent role correctly:

  • Ecosystem ROLE LIBRARY contains the row; ROLE DETAIL renders purpose + persona on selection; SKILLS / MCP SERVERS tables show echo + echo_server (PR-A path-resolution fix exercised end-to-end).
  • Schedule infusion → Nucleus dispatches the right RolePreloadMessage.
  • Prompt pane (screen 7) defaults the target_role Select to coding_agent; Send publishes a TASK_ASSIGN with optional target_agent_id pinning (PR-B filter on the agent side).
  • Performance screen (PR feat(tui): capability invocation telemetry on Performance screen #15) renders capability telemetry + recent failures from synthetic TASK_COMPLETEs sourced from a coding_agent-* agent_id, including A-017 block reasoning.

Tests (10 new, all green)

Group Cases
Ecosystem role row, role detail render, skills table, mcps table, Schedule-infusion dispatch
Prompt pane default target = coding_agent, send routes target_role, send with target_agent_id pins to specific agent
Performance telemetry table records skill:echo invocation, failures panel renders A-017 block from coding_agent

Implementation patterns reused

  • `_capture_static_updates` (PR-A trick to read `Static.update` calls across Textual versions).
  • `_StubObserver` channel harness (PR-B pattern).
  • Synthetic `TASK_COMPLETE` via `observer._route_task_complete` (PR feat(tui): capability invocation telemetry on Performance screen #15 telemetry test pattern).
  • Synthetic `DataTable.RowSelected` event (PR-A pattern, more deterministic than `pilot.press("enter")`).

Test plan

  • `pytest tests/test_coding_agent_tui_pilot.py -v --no-cov` → 10 passed in 9s (locally on Windows)
  • Combined regression (15 test files) → 238 passed, 6 deselected
  • acc1 was unreachable at PR-creation time (SSH timeout to 10.199.12.91:22 — also true at the previous PR test(coding_agent): pin schema invariants for the demonstrator role (Tier A) #21). Tests are pure-Python (no platform-specific code) and will transfer cleanly once acc1 is back.

Files

File Change
`tests/test_coding_agent_tui_pilot.py` (new) 10 cases.

Out of scope (next test-tier follow-ups)

  • Tier C — Live container integration via the coding-split profile. Opt-in via `ACC_LIVE_TESTS=1` + a running stack so CI doesn't hang on a missing NATS.
  • Tier D — Negative paths: missing role dir → graceful EcosystemScreen degradation; `target_agent_id` mismatch → drop; HIGH-risk skill blocked by A-017 ceiling.

…ier B)

Tier B of the coding_agent test plan (Tier A — schema invariants —
landed in #21).  Verifies that the canonical TUI surfaces consume
the ``coding_agent`` role correctly:

* Ecosystem ROLE LIBRARY contains the row.
* ROLE DETAIL panel renders the role's purpose + persona on selection.
* SKILLS / MCP SERVERS tables list echo + echo_server.
* "Schedule infusion → Nucleus" button dispatches RolePreloadMessage
  with role_name='coding_agent'.
* Prompt pane (screen 7) defaults the target_role Select to
  coding_agent; Send publishes a TASK_ASSIGN with target_role +
  optional target_agent_id pinning.
* Performance screen (PR #15) renders the CAPABILITY INVOCATIONS
  table + RECENT FAILURES panel from synthetic TASK_COMPLETEs
  sourced from a coding_agent-* agent_id, including A-017 block
  reasoning.

tests/test_coding_agent_tui_pilot.py (NEW, 10 cases all green):

  Ecosystem (5):
    test_ecosystem_role_library_row_for_coding_agent
      → ROLE LIBRARY contains the coding_agent row keyed by name.
    test_ecosystem_role_detail_renders_coding_agent_seed
      → on RowSelected, ROLE DETAIL Static carries the role.yaml
        purpose phrase verbatim + the "analytical" persona.
    test_ecosystem_skills_table_shows_echo_for_coding_agent_role
    test_ecosystem_mcps_table_shows_echo_server_for_coding_agent_role
      → both confirm PR-A's path-resolution fix loads the repo's
        skills/ + mcps/ correctly even when the test runner's cwd
        differs from the repo root.
    test_schedule_infusion_button_dispatches_role_preload_for_coding_agent
      → Send button posts RolePreloadMessage(role_name='coding_agent')
        the App routes to InfuseScreen.preload_from_role.

  Prompt pane (3):
    test_prompt_pane_target_role_defaults_to_coding_agent
      → guards a regression where the default Select value drifts.
    test_prompt_send_routes_task_assign_to_coding_agent
      → Send publishes TASK_ASSIGN with target_role='coding_agent',
        no target_agent_id (broadcast-by-role behaviour).
    test_prompt_send_with_target_agent_id_pins_to_specific_coding_agent
      → operator-supplied target_agent_id makes it onto the wire so
        PR-B's filter on the agent side only lets the named agent
        process the task.

  Performance screen (2):
    test_performance_telemetry_records_coding_agent_skill_invocation
      → coding_agent emits a skill:echo invocation in TASK_COMPLETE
        → CAPABILITY INVOCATIONS table renders one row keyed
        ``skill:echo``.
    test_performance_failures_panel_renders_a_017_block_from_coding_agent
      → coding_agent attempts shell.exec → Cat-A A-017 blocks →
        RECENT FAILURES panel shows shell.exec + A-017 + the
        coding_agent agent_id (truncated).

Implementation patterns reused from earlier PRs:
  * ``_capture_static_updates`` — PR-A trick to read Static.update
    calls across Textual versions.
  * ``_StubObserver`` (channel-shape) — PR-B harness for prompt-pane
    pilot tests.
  * Synthetic TASK_COMPLETE delivery via ``observer._route_task_complete``
    — PR #15 telemetry test pattern.
  * Synthetic ``DataTable.RowSelected`` event — PR-A pattern, more
    deterministic than ``pilot.press("enter")``.

Combined regression: 238 unit tests pass on Windows
(test_coding_agent_role + test_coding_agent_tui_pilot +
test_task_progress_emit + test_task_progress_streaming +
test_prompt_screen_pilot + test_prompt_channel +
test_observer_task_listener + test_redis_compat +
test_capability_telemetry + test_ecosystem_screen_pilot +
test_file_picker_pilot + test_config + test_role_store +
test_guardrails + test_compliance, with TestEd25519Validation
deselected for the lighthouse OpenSSL platform limit).

Out of scope (next two follow-up PRs):
* Tier C — Live container integration via the coding-split profile.
  Opt-in via ACC_LIVE_TESTS=1 + a running stack so CI doesn't hang
  on a missing NATS.
* Tier D — Negative paths: missing role dir → graceful EcosystemScreen
  degradation, target_agent_id mismatch → drop, HIGH-risk skill
  blocked by A-017 ceiling.
@flg77
flg77 merged commit 9efee21 into main May 1, 2026
@flg77
flg77 deleted the feat/coding-agent-tier-b-pilot-tests branch May 1, 2026 15:23
flg77 added a commit that referenced this pull request May 1, 2026
Tier D of the coding_agent test plan.  Tiers A (schema invariants,
PR #21) and B (Pilot happy-path TUI flow, PR #22) covered the
positive contract; this file pins the failure-mode contract so a
future refactor cannot silently weaken the safety surface around
the demonstrator role.

tests/test_coding_agent_negative_paths.py (NEW, 9 cases all green):

  Negative path 1 — missing role directory (1):
    test_ecosystem_renders_without_crashing_when_coding_agent_missing
      Mirror live roles/ tree to a tmp dir, delete the
      coding_agent subtree, point ACC_ROLES_ROOT at the doctored
      tree.  EcosystemScreen MUST mount cleanly with the
      demonstrator row absent — not raise an AttributeError or
      leave the screen blank.  Confirms the screen survives the
      operator-removes-coding-agent footgun (rename, accidental
      rm, container volume mishap).

  Negative path 2 — target_agent_id mismatch (3):
    Replicates PR-B's inline filter from Agent._task_loop._handle_task:
        target_aid = data.get("target_agent_id")
        if target_aid and target_aid != self.agent_id:
            return
    test_target_agent_id_mismatch_drops_silently
      → coding_agent-aaa pinned by the prompt pane;
        coding_agent-bbb sees the same TASK_ASSIGN on the bus →
        silently drops.
    test_target_agent_id_missing_or_empty_falls_through_to_broadcast
      → missing key, None, "" all treated as broadcast — covers
        legacy producers (Slack pre-PR-B, manual acc-cli publishes).
    test_handle_task_filter_matches_agent_py_implementation
      → smoke check that the filter we test is actually the one
        shipped in acc.agent.  Catches a refactor that splits the
        filter into a helper without preserving the semantics.

  Negative path 3 — risk ceiling enforcement (2):
    test_high_risk_skill_blocked_by_a_017_against_coding_agent
      → HIGH-risk skill manifest, role's max_skill_risk_level is
        MEDIUM (Tier A pin) → A-017 blocks even when the skill
        IS in allowed_skills.  Confirms the risk-ceiling check is
        the second-line defence — an operator allow-listing a
        risky skill via a typo on role.yaml does NOT bypass the
        ceiling.
    test_critical_skill_blocked_against_coding_agent_default_role
      → CRITICAL covers the upper bound of the risk ladder.

  Negative path 4 — whitelist enforcement (3):
    test_unknown_skill_blocked_by_a_017_whitelist
      → skill_id missing from allowed_skills → A-017 reason
        names the missing id + lists the whitelist for audit-log
        consumers.
    test_dispatch_invocations_surfaces_a_017_block_as_outcome_error
      → end-to-end through dispatch_invocations: outcome carries
        ok=False + error string mentioning A-017 + the offending
        skill_id; underlying adapter never runs.  Operators see
        this in the prompt-pane transcript trace lines (✗ red) and
        the Performance screen RECENT FAILURES panel.
    test_a_017_block_does_not_skip_neighbour_invocations
      → first invocation denied, second invocation allowed →
        BOTH outcomes returned in source order, second adapter
        runs.  Confirms the operator's task isn't dropped when
        one of N markers fails the guard.

Combined regression: 252 unit tests pass on Windows
(test_coding_agent_role + test_coding_agent_tui_pilot +
test_coding_agent_negative_paths + test_task_progress_emit +
test_task_progress_streaming + test_capability_dispatch_oversight +
test_prompt_screen_pilot + test_prompt_channel +
test_observer_task_listener + test_redis_compat +
test_capability_telemetry + test_ecosystem_screen_pilot +
test_file_picker_pilot + test_config + test_role_store +
test_guardrails + test_compliance, with TestEd25519Validation
deselected for the lighthouse OpenSSL platform limit).

Tier C (live container integration via the coding-split profile)
remains a separate follow-up — opt-in via ACC_LIVE_TESTS=1 + a
running stack so CI doesn't hang on a missing NATS, plus acc1 is
currently unreachable for the smoke run.

acc1 verification deferred — host SSH was unreachable at PR-21
and PR-22 creation time too.  Tests are pure-Python (no platform
specifics) so the local Windows result transfers cleanly when
acc1 is back.
flg77 added a commit that referenced this pull request Jun 5, 2026
…surface)

Eighth and final sub-slice of Stage 1
(openspec/changes/20260605-acc-pkg-trust-and-assistant/).  Lands the
declarative DC install API surface — the GitOps seam for Stage
1.5.3's pkg-install code path.

What ships:

  * operator/api/v1alpha1/acccatalog_types.go (NEW):
    - AccCatalog CRD mirroring acc.pkg.catalog.Catalog Pydantic
      model so the operator's rendered YAML validates cleanly
      against the Python loader.
    - Spec fields: catalogId, tier (trusted|tp|community|self),
      mode (https|file), url|path, requiredSigner (issuer +
      subjectPattern + optional keyPath), priority.
    - Status fields: observedGeneration, conditions[],
      lastRenderedAt.
    - Printcolumns + shortNames for kubectl-friendly UX.

  * operator/api/v1alpha1/accpackageinstall_types.go (NEW):
    - AccPackageInstall CRD — one @scope/name@constraint install.
    - Spec fields: name (regex-validated), constraint, catalogRef
      (optional pin), targetCorpus (optional scope), allowUnsigned
      (operator-explicit bypass).
    - Status fields: phase (Pending|Installing|Installed|Failed),
      installedVersion, installPath, contentSha256, lastInstalledAt,
      conditions[].

  * operator/api/v1alpha1/zz_generated_stage1_6_deepcopy.go (NEW):
    - Hand-written DeepCopy / DeepCopyObject methods following
      controller-gen's emission style.  Replace on next
      `make generate`.

  * gitops/argocd/applications/accpackage-sample.yaml (NEW):
    - End-to-end ArgoCD Application driving two AccCatalog entries
      (canonical https + corp-internal file-mode) + two
      AccPackageInstall objects.  Operators copy + adjust the
      catalog URL + signer pattern for their environment.

  * gitops/argocd/applications/README.md (NEW):
    - Documents what Stage 1.6 ships (API + sample) vs what's
      deferred to 1.6b (reconcilers + RBAC + OLM bundle +
      envtest).  The deferred reconciler consumes the same
      fetch_and_install Python entry point that 1.5.3 and 1.4
      already use — single seam, no parallel logic.

Design choices:

  * API surface lands now so downstream GitOps tooling can import
    the types; reconciler logic (exec-into-pod, leader election,
    status patching) is multi-day Go work and ships as 1.6b.
  * AccCatalog Spec mirrors acc.pkg.catalog.Catalog 1:1 — operator
    renders directly to /etc/acc/catalogs.yaml ConfigMap, no
    translation layer.
  * AccPackageInstall.spec.constraint accepts the same range syntax
    acc.pkg._semver implements; operator does shape validation, the
    installer is the resolution authority.
  * AllowUnsigned at the CR level so dev-environment opt-out is
    declarative + audit-logged via the controller's events.

Tests: no new Python tests (Go-only changes; Python pkg suite
unchanged at 415/1 green).  Go envtest integration tests land in
1.6b alongside the reconciler.  Manifest sample YAML parses (5
documents: Application + 2 AccCatalog + 2 AccPackageInstall).

This completes Stage 1's eight sub-slices:
  1.5.1 dual-source role loader (#21)
  1.5.2 required_packages (#22)
  1.5.3 acc-deploy.sh boot-time fetch (#23)
  1.4   PROPOSE_INFUSE marker (#24)
  1.1   eval format (#25)
  1.2   EC policy depth (#26)
  1.3   OIDC keyless publish (#27)
  1.6   operator CRDs (this)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
flg77 pushed a commit that referenced this pull request Jun 15, 2026
GHSA-gv7w-rqvm-qjhr)

esbuild was pulled transitively at 0.25.12 (< 0.28.1) by vite 6, which
pins esbuild to the 0.25.x line — no fix available within ^6. Forcing
esbuild 0.28.1 under vite 6 breaks the build (0.28 won't down-transform
destructuring to vite 6's old target). Bump vite to ^7 (+ @vitejs/plugin-react
^5) which builds cleanly, and add an overrides pin esbuild ^0.28.1 to land
the patched version (vite 7 alone resolves esbuild 0.27.7, still < 0.28.1).

Verified on node 22 (the ubi9/nodejs-22 build image): npm ci in sync,
esbuild 0.28.1 installed, 'npm run build' (tsc -b && vite build) passes.

Resolves Dependabot alert #22 (high). esbuild is a build-time dev dep and
the advisory's vector is Deno-specific, but patched regardless.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
flg77 added a commit that referenced this pull request Jun 15, 2026
fix(webgui): bump vite 6→7 + pin esbuild ^0.28.1 (Dependabot #22, high)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant