Skip to content

feat(work): A-class UI surfaces + B.6 SubAgent acceptance/reviewer 闭环#28

Merged
TYRMars merged 2 commits into
mainfrom
feat/OTel
May 8, 2026
Merged

feat(work): A-class UI surfaces + B.6 SubAgent acceptance/reviewer 闭环#28
TYRMars merged 2 commits into
mainfrom
feat/OTel

Conversation

@TYRMars
Copy link
Copy Markdown
Owner

@TYRMars TYRMars commented May 8, 2026

Summary

This PR closes the A-class UI 串联缺口 (5 surfaces) and the B-class SubAgent acceptance policy + reviewer auto-accept loop end-to-end.

A class — UI 串联缺口 (5/5)

1. Auto-mode dashboard (/projects/auto-mode)

Backend now exposes scheduler liveness; new page makes it actionable.

  • Backend
    • Extended GET /v1/auto-mode payload: now returns mode, tick_seconds, max_concurrent_units, available_permits, last_tick_at, max_units_per_tick, max_retries, run_timeout_ms, allow_unassigned, default_assignee alongside the legacy enabled / configured
    • AutoModeRuntime::record_tick() stamps wall-clock time on every tick (regardless of enable flag — operators can see "loop alive, just paused")
    • New GET /v1/diagnostics/runs/recent?limit=N reusing existing RequirementRunStore::list_all, sorted by finished_at (or started_at for in-flight)
    • AppState.auto_mode_config: Option<Arc<AutoModeConfig>> snapshot stashed at boot
  • Frontend (AutoModeDashboardPage.tsx)
    • Scheduler header strip (toggle + read-only config + available_permits / max_concurrent_units gauge + last-tick relative time)
    • 5 panels: in-flight runs / recent runs / recent failures (with Retry → mints fresh run) / Pending triage (cross-project) / Blocked-or-waiting (client-side derivation: missing assignee, unmet deps, retries exhausted)
    • Per-run detail drawer (GET /v1/runs/:id): logs, usage, error, verification
    • 5s poll + window-focus refresh
    • Sidebar nav "自动调度 / Auto-mode" + WorkOverview header link

2. Triage 增量

  • TriageDrawer 新增 "全部通过 (N)" 按钮 (parallel approveRequirement, confirm before)
  • Cross-project Pending triage panel in Auto-mode dashboard with deeplink to project kanban

3. Conversation history (/conversations + /conversations/:id)

  • New full-page archive: search box + project filter + date grouping (reuses convoGroupLabel)
  • Click row → resumeConversation(id) then navigate to /
  • /conversations/:id deep-link: resume + redirect (clean browser history, no junk page)
  • Sidebar nav "全部会话 / All conversations"

4. Worktree management (/projects/worktrees)

  • Reuses existing /v1/diagnostics/worktrees/orphans + /cleanup
  • Lists orphans with size (auto KiB / MiB / GiB), modified-time, run id
  • Red Cleanup button with confirm; renders last-cleanup report (removed / failed)
  • 15s poll + window-focus refresh + clear empty/disabled/error states
  • Sidebar nav "Worktree 管理 / Worktrees"

5. Plan-mode chat UX

  • Investigation showed backend + frontend were 95% wired (PlanProposedCard, accept_plan / refine_plan frames, requirementhttp.review_verdict tool — all in place)
  • The gap: when user switched to Plan but no plan was proposed yet, no UI feedback existed
  • New PlanModeBanner mirrors BypassBanner: visible when permissionMode==="plan" && !proposedPlan, with Exit plan mode button (→ ask)

B.6 SubAgent — acceptance policy 全栈闭环

Requirement.acceptance_policy (Subagent / Human) frontend wiring

The field shipped on harness-core months ago but had no UI surface and was inert at runtime. This PR makes it real.

  • Backend (requirements_routes.rs)
    • PATCH /v1/requirements/:id accepts acceptance_policy: "subagent" | "human" — invalid value → 400
    • Activity row written when policy flips: Comment{kind:"acceptance_policy_change", from, to}
  • Frontend
    • AcceptancePolicy type + Requirement.acceptance_policy? field in types/frames.ts
    • updateRequirement(id, { acceptance_policy }) in services/requirements.ts
    • AcceptancePolicyRow (Select + hint) in RequirementDetail.tsx
    • Orange "人工验收 / human review" badge on kanban card when acceptance_policy === "human"

auto_mode 真正读 acceptance_policy

  • completed_requirement_target_statusHuman policy 下停在 Review 而非 Done
  • tick eligibility filter 跳过 Human policy 的 Review 行 (避免 picker 无限重选)

Reviewer auto-accept dispatch (opt-in via JARVIS_REVIEWER_AUTO_ACCEPT)

  • Off by default — existing deployments keep pre-v1.0 auto-flip semantics
  • When enabled: Subagent policy + Completed run → row holds at Review + dispatches subagent.review from state.tools with {task, context: {requirement_id, run_id, verification_plan, work_summary}}
  • Reviewer subagent's terminal call to existing requirement.review_verdict tool flips Review → Done (pass) or Review → InProgress (fail) with commentary attached
  • 2 new Activity rows: Comment{kind:"reviewer_dispatched"} + Comment{kind:"reviewer_dispatch_failed", error} if dispatch errors out (tool missing, etc.)

Tests + quality gates

  • 232/232 harness-server unit tests pass
  • 6 new tests covering acceptance_policy + reviewer dispatch:
    • tick_skips_human_acceptance_policy_at_review
    • tick_advances_human_policy_in_progress_to_review
    • completed_target_status_respects_acceptance_policy (pure unit, all combinations)
    • advance_dispatches_reviewer_when_flag_enabled_and_policy_subagent (mock reviewer tool)
    • advance_skips_dispatch_when_flag_disabled
    • advance_skips_dispatch_for_human_policy_even_with_flag_enabled
    • dispatch_acceptance_review_errors_when_tool_missing
  • cargo clippy --workspace --all-targets -- -D warnings clean
  • cargo build -p jarvis succeeds (web bundle baked in via include_dir!)
  • All new strings i18n-complete (en + zh)

Note: bundled scaffolding

This PR also bundles in-flight Observability + EvalStore scaffolding (HarnessObservabilityPanel, observability_routes.rs, EvalStore trait, harness-store backend additions, self-improving-agent.zh-CN.md proposal) that was already in the working tree. Those changes were entangled with state.rs / routes.rs / lib.rs hunks and couldn't be cleanly separated at the file level. They build + test cleanly but are scaffolding only — full OTel/eval wiring is a separate workstream tracked under feat/OTel.

Test plan

  • Cold-start the binary with no env vars; visit /projects/auto-mode — page loads, scheduler shows "configured: false" or "paused" depending on env
  • Set JARVIS_WORK_MODE=auto JARVIS_WORK_TICK_SECONDS=5; restart; dashboard shows mode=auto, tick=5s, last_tick updates every 5s
  • Visit /conversations; search + project filter behave; clicking a row resumes
  • Visit /projects/worktrees; empty state when worktree feature off; cleanup button when orphans exist
  • In a project kanban, open a Requirement detail; flip Acceptance to "Human review only"; the kanban card grows the "人工验收" badge
  • With JARVIS_REVIEWER_AUTO_ACCEPT unset, complete a Subagent-policy requirement → row flips to Done (current behavior)
  • With JARVIS_REVIEWER_AUTO_ACCEPT=1, same scenario → row holds at Review and subagent.review is invoked (visible in Activity timeline as reviewer_dispatched)
  • In chat, switch permission mode to "Plan" → blue banner appears; click "Exit plan mode" → switches back to Ask, banner unmounts

🤖 Generated with Claude Code

TYRMars and others added 2 commits May 8, 2026 12:40
A class — UI 串联缺口 (5/5)
  • Auto-mode dashboard at /projects/auto-mode
    - Backend: extended GET /v1/auto-mode payload (config + permits +
      last_tick_at), AutoModeRuntime::record_tick(), new
      GET /v1/diagnostics/runs/recent reusing
      RequirementRunStore::list_all
    - Frontend: scheduler header strip, in-flight runs, recent runs,
      recent failures (with Retry → POST /v1/requirements/:id/runs),
      blocked/waiting derivation, per-run drawer (logs/usage/error),
      cross-project Pending-triage panel
  • Triage 增量
    - TriageDrawer 加 "全部通过 (N)" 按钮 (parallel approveRequirement)
    - cross-project pending callout in Auto-mode dashboard
  • Conversations archive
    - new /conversations browse page (search + project filter +
      date grouping) + /conversations/:id deep-link redirect
  • Worktrees panel at /projects/worktrees
    - reuses /v1/diagnostics/worktrees/orphans + cleanup, with
      size formatting, age, confirm-before-delete, last-cleanup report
  • Plan-mode chat UX
    - PlanModeBanner mirrors BypassBanner; visible when
      permissionMode==plan && !proposedPlan; "Exit plan mode" → ask

B.6 SubAgent — acceptance policy 全栈闭环
  • Requirement.acceptance_policy (Subagent / Human) 前端通路
    - PATCH /v1/requirements/:id 接受 acceptance_policy
    - types/frames.ts: AcceptancePolicy + Requirement.acceptance_policy
    - RequirementDetail Select picker + kanban "human review" badge
  • auto_mode 真正读 acceptance_policy
    - completed_requirement_target_status 在 Human policy 下停在
      Review 而非 Done
    - tick eligibility filter 跳过 Human-policy 的 Review 行
      (避免无限重选)
  • Reviewer auto-accept dispatch (opt-in via JARVIS_REVIEWER_AUTO_ACCEPT)
    - AutoModeConfig.reviewer_auto_accept (default false)
    - dispatch_acceptance_review 从 state.tools 解析
      subagent.review,构造 task + context (req_id / run_id /
      verification_plan) 并调用; reviewer 通过其
      requirement.review_verdict 工具自己写最终状态
    - Activity rows: reviewer_dispatched + reviewer_dispatch_failed

Tests
  • 232/232 harness-server unit tests pass
  • 6 new tests:
    - tick_skips_human_acceptance_policy_at_review
    - tick_advances_human_policy_in_progress_to_review
    - completed_target_status_respects_acceptance_policy
    - advance_dispatches_reviewer_when_flag_enabled_and_policy_subagent
    - advance_skips_dispatch_when_flag_disabled
    - advance_skips_dispatch_for_human_policy_even_with_flag_enabled
    - dispatch_acceptance_review_errors_when_tool_missing
  • cargo clippy --workspace --all-targets -D warnings 干净

i18n
  • 全部新增字符串 en + zh 双语 (auto-mode dashboard, conversations
    archive, worktrees page, plan-mode banner, acceptance policy,
    triage approve-all, sidebar nav entries)

Note: this commit also bundles in-flight Observability + EvalStore
scaffolding (HarnessObservabilityPanel, observability_routes,
EvalStore trait) that was already in the working tree and is now
entangled with state.rs / routes.rs hunks. Those changes build +
test cleanly but are scaffolding only — full OTel/eval wiring is
a separate workstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `setProjectFilter`'s state type was `string | "all"`, which eslint's
  `no-redundant-type-constituents` flags because `string` already
  swallows `"all"`. Drop the union — we use `"all"` only as a
  sentinel string in a single equality check.
- The row click handler was an `async () => {}` calling
  `await resumeConversation(...)` then `navigate("/")` —
  `no-floating-promises` (and `no-misused-promises` on the prop)
  reject async event handlers. Rewrite as a sync handler that
  calls `void resumeConversation(...).then(navigate)`.

Verified: `npx eslint src` exits 0 (was failing on CI); `tsc
--noEmit` clean; `vite build` succeeds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@TYRMars TYRMars merged commit 66e5479 into main May 8, 2026
1 of 2 checks passed
TYRMars pushed a commit that referenced this pull request May 10, 2026
Bumps `[workspace.package].version` from 0.1.0 to 0.2.0 (cascades to
every member crate via `version.workspace = true`) and reframes the
existing `## Unreleased` block as the `0.2.0` release.

The 0.2.0 entry consolidates four PRs that landed since this CHANGELOG
was first introduced:

- PR #28 (OTel + model registry): observability stack, model registry +
  routing policy + capability-validating provider profile, fallback UI,
  Customize / Market panels, jarvis-cli telemetry/web subcommands.
- PR #29 (model + session race fix): session-switch race repair around
  `conversation <uuid> not found`, scoped-frame invariants, 4 new
  vitest cases.
- PR #30 (channels + sidebar + auto-mode refactor): WeCom WebSocket
  gateway adapter, Channels REST + Settings section, Codex-style chat
  sidebar with project groups, ~700 LOC trimmed from auto_mode.rs,
  RUN_TIMEOUT default 5m → 10m.
- PR #31 (Makefile + docs): align local cargo commands with CI's
  `--exclude jarvis-desktop` invariant.

Plus the original CHANGELOG-introducing PR's web composer / workspace
probe / WS metadata work.

Verified: `cargo check --workspace --exclude jarvis-desktop` passes,
Cargo.lock picks up the version bump (25 entries flipped).

`## Unreleased` is left as a fresh "_No changes yet._" placeholder so
future PRs have an obvious place to land.
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