xworkmate-app/docs/testing/app-external-service-api-test-matrix.md
Haitao Pan 6478f325f6
ci(release): load Vault secrets per-platform in build matrix (#44)
* fix(artifacts): prioritize PDF deliverables in sidebar

* docs(cases): add gateway turn acceptance summary

* ci: add release/* branch source validation workflow (#19)

release/* 仅接受 hotfix/* 或带 cherry-pick/backport 标签的 PR。
详见 iac_modules/docs/tldr-github-branch-model.md

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* ci: run desktop integration/patrol tests under xvfb (#22)

Headless Linux runners have no display, so 'flutter test integration_test'
fails to launch the GTK app ('The log reader stopped unexpectedly, or never
started'). Wrap integration/patrol layers in xvfb-run with a 24-bit screen
and install xvfb + mesa DRI driver for headless GL. macOS/local runs are
unaffected (no xvfb-run -> command runs directly).

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* fix: reveal artifact files without blocking

* fix: reveal artifact files without blocking (#20)

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>

* Release/v1.1.5 (#25)

* ci: backport release/* source validation workflow to release/v1.1.5 (#21)

让现有 release/v1.1.5 分支自身包含门禁 workflow(pull_request_target 用 base 分支版本)。
详见 iac_modules/docs/tldr-github-branch-model.md

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* fix: reveal artifact files without blocking (#24)

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>

---------

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* chore: update tested linux labels (#23)

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>

* chore: sync app version to 1.1.5 (#26)

* fix: keep stopped gateway tasks out of pending queue

* chore: add ios release verification assets

* Fix managed bridge token priority

* fix: stabilize iOS login storage and mobile settings

* Refine assistant attachment payload handling

* Fix assistant continue task requeue

* Fix mobile account sign-in flow

* Fix ACP SSE no-result recovery

* Polish assistant UI and add Service Mesh video case

* feat(mobile): redesign mobile UX and iOS native experience

* feat(mobile): move configuration chips to + menu and add left drawer

* feat(mobile): redesign mobile ui to chatgpt minimalist style

* fix(mobile): tweak composer submit button size and wire up settings drawer

* fix(mobile): remove background from send button

* fix(mobile): use blue circle with upward arrow for send button

* feat(mobile): add navigation breadcrumb to return to chat from settings

* feat(mobile): refine composer ui with minimalist modern aesthetic

* Remove OpenClaw direct ACP route

* Add desktop navigation integration test

* Add desktop settings integration test

* Use remote workspace for OpenClaw execution

* Handle gateway default task workspace

* Keep sidebar task order stable

* Hide desktop agent dialog mode

* Release v1.1.3

* Fix Apple preflight for main builds

* Fix Apple preflight for main builds

* Fix Apple preflight for main builds

* Add bulk archive task selection

* Fix assistant skill picker loading

* Stabilize mobile provider sheet test

* chore: prepare v1.1.3 release metadata

* fix: unblock OpenClaw gateway task queue

* fix: keep running task follow-up in current thread

* fix: isolate openclaw e2e artifacts

* fix(assistant): pin task session on submit

* docs: record openclaw gateway e2e cases

* test: align openclaw e2e prompts

* refactor: classify gateway task load

* refactor: classify gateway task load

* feat: sync existing workspace directory artifacts recursively

* Use manual bridge config for ACP runtime

* Fix task refresh layout stability

* chore: update core integration cases and runtime helpers

* fix: stabilize complex openclaw artifact tasks

* fix: repair bridge login sync runtime state

* fix: repair bridge login sync runtime state

* Fix manual bridge save runtime config

* fix: use OpenClaw gateway protocol 4

* fix: use OpenClaw gateway protocol 4

* fix(openclaw): keep artifact runs session scoped

* chore(app): refresh build metadata

* fix(openclaw): recover final task snapshots

* fix(openclaw): recover long SSE task artifacts

* test(app): align thread artifact isolation assertions

* fix(openclaw): keep long artifact recovery synced

* feat(openclaw): implement artifact sync and ignore policies

* Reassociate OpenClaw tasks through Bridge control plane

* Preserve artifacts after interrupted bridge responses

* feat: Remote Desktop UI and Client WebRTC Integration

* refactor: simplify remote desktop UI and add maximize toggle

* fix(webrtc): pass SDP offer and answer as object to conform to backend format

* fix: revert sdpOffer to String to match Bridge SDP expectations

* feat: add runtime logs tab to settings page

* chore: prepare release v1.1.4 (app store compliance, remote desktop fixes, ci verification)

* fix: load nested bridge skills status

* fix(ci): parse provider catalog and gateway providers from capabilities fallback

* test: stabilize OpenClaw gateway active slot regression

* fix: WebRTC remote desktop connection, cleanup local fallback, and ignore .gradle cache

* feat: add collapse toggle to desktop control panel

* fix(runtime): restore skills loading and group rendering

* refactor(ui): eliminate unowned helper sprawl in assistant skill picker

* feat: improve webrtc keyboard mapping and add adaptive resolution default

* feat: improve webrtc keyboard mapping and add adaptive resolution default

* refactor(skills): clean Path B, add retry + auto-refresh, fix silent failures

- Remove Path B (direct WebSocket RPC), unify skills loading via ACP bridge sessionClient
- Delete skillsStatusPayloadInternal fragile nested-key parsing
- SkillsController: explicit error when offline (no more silent empty), auto-retry with 2s/4s backoff
- Auto-refresh on gateway connect via ChangeNotifier listener
- Gateway connect: concurrent Future.wait for independent controller refreshes
- UI: retry button in skill picker empty/error states
- Clean up skillsController from relayChildChangeInternal listeners

* refactor(skills): fix allowErrorPayload validation, improve auto-refresh guard

* feat(ui): apply BoxFit.fill for remote desktop WebRTC view to ensure no blank spaces

* refactor: remove multi-agent orchestration subsystem (Path B)

Remove the entire multi-agent collaboration execution path, including:
- MultiAgentOrchestrator and its 4-phase pipeline (Architect→Engineer→Tester→Iteration)
- ARIS framework preset and mount infrastructure
- Hardcoded model defaults (kimi-k2.5, minimax-m2.7, glm-5)
- Deprecated runCliPromptInternal() and its fallback call chain
- All related types: MultiAgentConfig, AgentWorkerConfig, MultiAgentRole, etc.

This collapses the architecture to a single clean path:
Flutter → GoTaskServiceClient → ACP Transport → Go Bridge → Remote Execution

2886 lines removed across 41 files.

* docs(cases): clean up test cases — remove ai-security-evolution scenario, fix issues

- Delete ai-security-evolution-content-scenario/ (8 files, referenced by removed MANUAL-LOCAL-001A)
- Remove MANUAL-LOCAL-001A from core-integration-manual-cases.md
- Fix duplicate section numbering (#5#6 for general thread scenarios)
- Remove misplaced workspace sync rules from MANUAL-ACP-004 (bridge auth case)
- Update README.md index

* test,docs: fix all stale references to deleted multi-agent subsystem

Test fixes (6 files, -303 lines):
- Delete app_controller_acp_mount_resilience_test.dart (entirely about deleted types)
- Remove multi-agent test cases from gateway_acp_client_auth_test.dart
- Rename _manifestWithDesktopMultiAgentEnabled → _defaultDesktopManifest
  in assistant_execution_target_test, assistant_lower_pane_test,
  mobile_assistant_page_test

Docs fixes (6 files):
- Regenerate public-symbol-inventory.json/md via make docs-public-api
- Remove multi-agent sections from public-api/models-and-config.md,
  app-orchestration.md, runtime-contracts.md
- Fix xworkmate/ → xworkmate-app/ paths in cloud-session doc
- Remove multiAgent references from app-external-service-api-test-matrix.md

* docs: add architecture README with categorized navigation

* docs(architecture): fix critical accuracy errors, stale refs, paths

Accuracy fixes:
- app-orchestration.md: remove non-existent constructor params
- models-and-config.md: remove wrong multiAgent field from SettingsSnapshot
- runtime-contracts.md: add missing multiAgent/collaborationMode/routingHint fields

Stale multi-agent refs:
- unified-routing-architecture.md: agent/multi-agent → agent (含 bridge 转发)
- bridge-runtime-routing-map.md: multi-agent tasks → multi-agent forwarding tasks
- cross-repo-task-state-workflow.md: remove multi-agent orchestration from mermaid
- runtime-contracts.md, feature-surfaces.md: 多 agent → agent

Organization:
- Move cloud-session-service and stage4-helper to archive/
- Fix 22 xworkmate/ → xworkmate-app/ paths in archive doc
- Fix XWorkmate.svc.plus repo name in simple-theme-default.md
- Update README.md index and public-api/README.md coverage stats (132/590)

* docs: rewrite README — fix repo name, remove stale multi-agent refs, add dependencies

- Title: XWorkmate → xworkmate-app
- Remove references to deleted multi-agent orchestration
- Fix download links: xworkmate.svc.plus → xworkmate-app
- Replace machine-specific /Users/shenlan/... paths with relative links
- Add Dependencies section: xworkmate-bridge, xworkspace-core-skills,
  openclaw-multi-session-plugins, playbooks
- Consolidate Learn More links to repo-relative paths

* fix desktop workspace stream fallback

* Fix WebRTC desktop video stream rendering and inputs

* refactor: eliminate dead codex_runtime methods, add anti-fallback policy

codex_runtime.dart (-290 lines):
- Remove 17 dead methods behind UnsupportedError guard
  (findCodexBinary, startStdio, request, startThread, resumeThread,
   sendMessage, interrupt, getAccount, listModels, listSkills, stop,
   dispose, _resolveLaunchConfiguration + 3 @visibleForTesting wrappers)
- Remove 10 dead fields (_process, _state, _pendingRequests, _events, etc.)
- Remove ChangeNotifier mixin (nothing to notify)
- Keep only model types, enums, and standalone helper functions

AGENTS.md (+21 lines):
- Add Fallback and Dead Code Elimination Policy section
- Forbidden: cascading fallbacks, lingering DEPRECATED code,
  dead code behind guards, silent catch blocks, redundant indirection,
  excessive JSON key probing
- Required: inline WHY comments on every retained fallback chain

Additional cleanup:
- gateway_acp_client.dart: remove unused _GatewayAcpSessionUpdate class
- runtime_controllers_entities.dart: replace _canRefreshThroughRuntime
  with runtimeInternal.isConnected
- runtime_models_gateway_entities.dart: relocate CollaborationAttachment

* Simplify RTCVideoView constraints and disable adaptive resolution by default

* refactor: remove stale runtime fallbacks

* fix: preserve openclaw failure artifacts

* fix: use default native track attach for desktop stream

* fix: poll openclaw task handle to terminal snapshot

* update architecture docs

* fix: finalize openclaw task polling results

* feat(xworkmate): optimize desktop thread actions and Go task service client

* docs: add cross-repo architecture chain maps and risk analysis

- Add 4 chain maps: task-execution, artifact-lifecycle, session-recovery, bridge-distributed
- Add cross-repo call analysis with top-10 fragile points
- Update AGENTS.md with 'Cross-Repo Architecture Chain Maps' section
- Document artifact path gap: OpenClaw tools output to ~/.openclaw/media/ but plugin export scans tasks/<session>/<run>/

* fix(webrtc): resolve remote desktop black screen by properly binding remote video tracks and removing legacy Plan B constraints

* fix: remaining webrtc stream and test artifact changes

* fix(arch): A1-A3 app layer anti-patterns cleanup

* fix(arch): conservative fallback for gateway error codes

* fix: merged cleanup branch and stashed fixes

* add design doc: multi-session-plugin-optimization

* fix: allow stopping archived tasks

* fix: sync openclaw terminal snapshots in app

* fix: resolve openclaw partial artifacts and eliminate legacy fallback code

* fix(assistant): clear pending tool calls when task completes to fix sticky running status

* refactor: Remove OpenClaw rigid time limits and false positive no-exported-artifacts judgment

* fix(ci): keep macos/ios build lanes running when Apple signing secrets are missing

The release preflight used to set should_build_platform=false whenever any
Apple signing secret was unset, which silently skipped the entire macos dmg
and ios ipa lanes (build + upload gated on that flag). Result: releases only
shipped linux, windows and android artifacts even when the iOS/macOS lanes
were otherwise healthy.

Make the preflight always release the lane, but emit a :⚠️: and
annotate the skip_reason when a secret is missing. The iOS branch in
build_matrix_artifacts.sh now picks the signed vs unsigned build path based
on actual secret availability instead of should_release alone, so it falls
back to flutter build ios --no-codesign + zip Runner.app whenever a secret
is absent. package-flutter-mac-app.sh already handled the no-secret case
locally (ad-hoc codesign --sign -) and needs no change.

Behavior matrix:
  macos: secret present -> signed DMG; secret missing -> unsigned DMG
  ios:   secret present + release -> signed IPA
         secret present + non-release -> unsigned zip
         secret missing (any) -> unsigned zip

* fix(chat): drop root-level expectedArtifactDirs to satisfy chat.send schema

- Remove the unexpected property at the root of gateway task metadata.
  Keep the value nested in xworkmateTaskArtifactContract where the
  OpenClaw chat.send schema allows it (-32002: invalid chat.send params).
- Drop dead local vars and the unused asInt helper in OpenClaw task
  association parsing.
- Remove the obsolete 'sendChatMessage restarts before handling
  OpenClaw artifact guard results' test superseded by the new terminal
  artifact failure test.

* fix(ci): drop ripgrep dependency from check-no-app-ffi.sh

The Flutter verification lane runs on Ubuntu 22.04 without ripgrep
installed, so the FFI integration guard silently fell through and
printed 'No app-side Codex FFI integration artifacts found' on every
run. Replace rg with the POSIX grep -RInE that ships with the runner,
keep the same excludes (check-no-app-ffi.sh, Pods, ephemeral, build,
.dart_tool) and emit the actual offending matches so the gate fails
loudly when a forbidden reference reappears.

* Document OpenClaw artifact dirs protocol boundary

* feat: pass OpenClaw artifact dir whitelist

* Remove Patrol from macOS package

* Add OpenClaw thin adapter refactor plan

* refactor/app-thread-key

* refactor: explicitly pass openclawSessionKey in task start

* Refactor OpenClaw task integration as thin adapter

* refactor: align OpenClaw session key state flow

* chore: retire rust ffi scaffold

* docs clarify openclaw artifact workspace ownership

* ci: read release secrets from vault

* fix: merge workflow env blocks

* fix: skip remote contract on push

* fix: align OpenClaw task key flow

* chore: retrigger workflow after vault data setup

* fix: backfill OpenClaw artifacts on sidebar refresh

* fix: trim OpenClaw task prompt context

* fix: keep OpenClaw artifact sync polling

* fix: require OpenClaw artifact export before completion

* fix: unify bridge auth token for desktop connect

* fix: keep bridge token usable after sync block

* fix: accept review bridge token from account sync

* fix: keep syncing partial OpenClaw artifacts

* Improve assistant task UX

* Sync artifact sidebar with selected task

* fix: show remote desktop first-frame state

* chore: log remote desktop WebRTC stats

* Stabilize OpenClaw artifact sync

* Add AI workspace management provisioning flow

* Fix gateway dispatch test pipeline

* Harden workspace prechecks

* Add AI workspace management provisioning flow

* Fix gateway dispatch test pipeline

* Harden workspace prechecks

* Relax workspace OS checks and add YAML import/export

* Relax workspace OS checks and add YAML import/export

* Make workspace advanced configs extensible

* Make workspace advanced configs extensible

* Clarify bridge DNS precheck message

* Clarify bridge DNS precheck message

* Relax workspace prechecks and add post-deploy validation

* Relax workspace prechecks and add post-deploy validation

* Improve workspace status summary wording

* Improve workspace status summary wording

* Add default bridge save action

* Add default bridge save action

* fix: isolate remote desktop webrtc sessions

* fix: isolate remote desktop webrtc sessions

* fix: smooth remote desktop input over webrtc

* fix: smooth remote desktop input over webrtc

* feat: align workspace ready actions and naming

* feat: align workspace ready actions and naming

* fix: clear desktop first-frame overlay after decode

* fix: clear desktop first-frame overlay after decode

* fix: use renderer first-frame signal for desktop video

* fix: use renderer first-frame signal for desktop video

* fix: split desktop mouse move data channel

* fix: split desktop mouse move data channel

* fix(app): bound OpenClaw artifact sync polling

* chore: remove stale Flutter code

* feat(assistant): include attachment source paths in gateway prompts

* chore(desktop): remove advanced options panel

* fix(desktop): bound WebRTC offer wait

* feat(workspace): run remote setup script

* fix: prioritize managed bridge sync state

* feat: add explicit gateway task case hints for openclaw-gateway-e2e-regression

* fix(settings): update account panel and assistant connection state

* fix: preserve primary bridge auth token

* test: ignore transient cleanup races

* fix: allow unsigned macos CI packaging

* fix: support macos validation on bash 3

* chore: temporarily disable desktop ai workspace

* ci: move remote_contract to test gate between build and release

Reposition the remote provider contract check as a skippable test-stage
quality gate (needs: build, continue-on-error) so it can never block
build or release. release uses always() to wait without being gated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore: update macOS deployment target to 14.0 and commit pending changes

* fix(gateway): day-1 stability — stop infinite "running" and un-stoppable tasks

Symptom: a gateway turn shows "任务运行中..." forever and 停止 has no effect,
even though the OpenClaw gateway has already finished (ACP_HTTP_CONNECTION_CLOSED).

- T3: add a hard deadline to the running-handle poll branch so the client no
  longer polls forever when tasks.get keeps returning "running". Budget is
  derived from taskLoadClass (10/30/60min, aligned with the bridge) + grace;
  on timeout the turn lands in a recoverable `interrupted` state
  (OPENCLAW_RUN_POLL_TIMEOUT) prompting the user to resend.
- T4: make 停止 locally authoritative — capture the association, mark the turn
  aborted immediately (clears pending, exits the poll loop), then fire
  tasks.cancel best-effort so a hung/failed cancel RPC can't block termination.
- T6: applyGatewayChatFailureInternal now authoritatively clears the pending
  flag (both raw + normalized key). Previously runOpenClawGatewayQueuedTurnInternal's
  finally never cleared it, leaving "error shown but still running".

Full cross-repo analysis + remaining TODO in docs/cases/06.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gateway): harden OpenClaw task recovery tests

* docs(cases/06): mark T7/T8/T9 done with impl locations & design trade-offs

Records the durable per-session run-registry implementation (bridge branch
fix/gateway-durable-run-registry): T7 gateway-unconfirmed fallback, T8 terminal
result cache, T9 DeadlineAt interrupt — with the trade-offs (no gatewayruntime
pending-map rewrite; per-session in-memory store not yet cross-restart durable;
T9 only force-terminates when the gateway is unconfirmed) and the test names that
cover each.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(cases): record local bridge runtime validation

* ci: refresh app workflows for node 24

* test: keep layered flutter tests aligned with repo

* test: align gateway recovery expectations

* test: stabilize assistant gateway recovery cases

* docs(cases/06): record definitive root cause — xworkmate.* gateway protocol drift

Adds the 2026-06-26 decisive finding: the bridge forwards `xworkmate.*` method
names the OpenClaw 2026.6.2 gateway does not implement (it uses native
tasks.get/list/cancel and artifacts.list/get/download). Documents the corrected
end-to-end turn timeline with the three break points (tasks.get unknown method;
{taskId}-only param shape + taskId!=runId; artifacts.* drift blocking .md delivery),
the evidence (gateway source + schema + CHANGELOG), the implemented task-lifecycle
fix, and the precisely-specified remaining work (artifact-method alignment + test
fixture migration). Corrects the earlier (wrong) "push/pull mismatch" conclusion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(cases/06): correct root cause — plugin not loaded, not protocol drift

Live verification disproved the earlier "xworkmate.* protocol namespace drift"
conclusion. The xworkmate.* gateway methods are REAL — registered at runtime by
the openclaw-multi-session-plugins plugin (index.ts registerGatewayMethod). The
actual failure: the running OpenClaw gateway did not load that plugin because its
source path was the ephemeral /private/tmp/openclaw-multi-session-plugins/... and
the gateway booted (09:21) ~9h before those files were populated (18:40), so it
started with 5 plugins (no multi-session) and every xworkmate.* returned
"unknown method". Restarting the gateway loads 6 plugins and the methods work
(errors shift to plugin-level param validation).

Changes:
- Add a corrected conclusion banner up top distinguishing the primary root cause
  (plugin load) from the T1-T9 robustness hardening.
- Replace the wrong "protocol drift / native alignment" section with the
  plugin-not-loaded root cause + evidence + the abandoned-branch note
  (fix/gateway-task-protocol-alignment must NOT be merged).
- Fix failure-row 10, T13 (runtime-state check now covers gateway plugin load),
  and the landing-order to put the plugin fix as step 0.
- Cross-reference openclaw-gateway-e2e-regression/ROOT_CAUSE_ANALYSIS.md (which
  was already correct about the 4-layer chain).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(cases/06): definitive 4-layer chain incl. multi-session plugin + live verification

Rewrites the timeline (§1) and topology (§2) as the correct FOUR-layer chain
App → bridge → openclaw-multi-session-plugins → OpenClaw gateway, and documents the
plugin's multi-session/multi-thread role: session mapping (appThreadKey⇄openclawSessionKey),
per-(session,run) artifactScope = tasks/<sanitize(sessionKey)>/<runId>, the strict
sessionKey/runId/artifactScope triplet validation, and the expectedArtifactDirs
workspace-root fallback scan.

Live-verified against 127.0.0.1:8787 (plugin loaded, commit 2333c3e):
- session.prepare returns a real mapping; chat.send returns runId; xworkmate.tasks.get
  is handled by the plugin but returns no_native_task_record with an empty task scope
  (chain reaches the plugin layer; the agent run produced no queryable task / no file —
  a layer-4 execution/landing issue).

Adds §7 stability improvements grounded in this live run:
- S0 install the plugin from a stable path (not /private/tmp) — the primary reliability fix.
- S1 expectedArtifactDirs was [] → the plugin's workspace-root fallback is inert; bridge
  should always pass default dirs (reports/, artifacts/).
- S2 no_native_task_record status ambiguity (running vs completed-without-artifact).
- S3 sessionKey/runId/artifactScope triplet consistency (don't pre-prefix agent:main:).
- S4 runtime observability across all four layers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(cases/06): S0 done — stable plugin install verified

Root cause of the plugin not loading was a symlink
~/.openclaw/extensions/openclaw-multi-session-plugins -> /tmp/... (ephemeral).
Replaced with a real dir, registered via `openclaw plugins install --force`,
restarted the gateway: now boots with "6 plugins ... openclaw-multi-session-plugins"
from the stable path, provenance warning gone, and xworkmate.session.prepare returns
the real plugin mapping (no bridge fallback). Survives restart.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(cases/06): mark S1 done — default expectedArtifactDirs (live-verified, bridge 0280893)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gateway): harden OpenClaw polling and acceptance notes

* docs(case06): close out acceptance log

* docs(case06): reconcile TODO status + consolidated cross-repo stability backlog

- Flip stale §5 checkboxes (T1/T2/T3/T4/T6) to done with code anchors —
  they had lagged behind §2/§6 which already marked them merged.
- Add §9: authoritative full-chain status across all 4 repos' main
  (app/bridge/openclaw/playbooks HEADs), the completed stability closure,
  and the precise remaining backlog (S1 redo, S2 status ambiguity, T8b
  cross-restart persistence) with acceptance criteria + anti-regression
  recommendations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(macos): suppress file selector deprecation warning

* docs(gateway): map durable agent terminal recovery

* docs(cases/06): 4-layer chain full live evaluation — end-to-end PASS

Live-verified one gateway turn across all four layers against 8787 (bridge 188ca4b,
gateway 6 plugins): session.start → real plugin session.prepare mapping → chat.send
→ xworkmate.tasks.get returns status=completed, constraintSatisfied=True, and
summary.md (438B) actually landed in tasks/<sani(sessionKey)>/<runId>/ and is
retrievable via xworkmate.artifacts.export. All xworkmate.* gateway methods ✓.
T12 metrics all 0 (no resilience fallback needed). Supersedes the earlier
no_native_task_record observation, which was a derived symptom of the plugin not
being loaded (the S0 symlink root cause).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(artifacts): route signed downloads through active bridge

* fix(prompt): simplify gateway workspace context to avoid conflicting paths (S5)

Every gateway turn's prompt prefix injected three near-duplicate absolute paths:
currentTaskWorkspace + localWorkspace + remoteWorkspaceHint. localWorkspace is the
App's LOCAL thread dir (~/.xworkmate/threads/...) which the gateway agent cannot
access, and remoteWorkspaceHint duplicates currentTaskWorkspace. The conflicting
paths leave the agent unsure where to work and can block conversation continuation.

For gateway turns the prompt now carries only currentTaskWorkspace (the plugin owns
the artifact scope); localWorkspace is kept only for non-gateway (local agent runs
there); remoteWorkspaceHint is dropped when equal to currentTaskWorkspace. sessionKey
is kept (short, not a path). UI is unaffected (chat bubble shows the raw user message;
the prompt-debug parser only special-cases Execution context / Preferred skills /
Attached files). Tests updated; assistant_execution_target_test green (74).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(macos): close file selector type branch

* fix(gateway): keep polling undecorated running snapshots

* docs(runbooks): record gateway turn stability case

* fix(artifacts): prioritize PDF deliverables in sidebar

* fix(artifacts): prioritize PDF deliverables in sidebar

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>

* docs(cases): add gateway turn acceptance summary

* ci: add release/* branch source validation workflow (#19)

release/* 仅接受 hotfix/* 或带 cherry-pick/backport 标签的 PR。
详见 iac_modules/docs/tldr-github-branch-model.md

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* ci: run desktop integration/patrol tests under xvfb (#22)

Headless Linux runners have no display, so 'flutter test integration_test'
fails to launch the GTK app ('The log reader stopped unexpectedly, or never
started'). Wrap integration/patrol layers in xvfb-run with a 24-bit screen
and install xvfb + mesa DRI driver for headless GL. macOS/local runs are
unaffected (no xvfb-run -> command runs directly).

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* fix: reveal artifact files without blocking

* fix: reveal artifact files without blocking (#20)

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>

* Release/v1.1.5 (#25)

* ci: backport release/* source validation workflow to release/v1.1.5 (#21)

让现有 release/v1.1.5 分支自身包含门禁 workflow(pull_request_target 用 base 分支版本)。
详见 iac_modules/docs/tldr-github-branch-model.md

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* fix: reveal artifact files without blocking (#24)

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>

---------

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* chore: update tested linux labels (#23)

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>

* chore: sync app version to 1.1.5

---------

Co-authored-by: Haitao Pan <manbuzhe2009@qq.com>
Co-authored-by: Cowork 3P <cowork-3p@localhost>
Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* fix(assistant): keep manual bridge usable when signed out of svc.plus

The gateway connection resolver short-circuited to "请先登录 svc.plus"
whenever the account was signed out, before checking whether a manual
bridge was configured or whether capability discovery was still running.
A saved manual bridge could therefore never be used while signed out.

- Only emit the signed-out prompt when neither an account session nor a
  manual bridge is configured (`!accountSignedIn && !bridgeConfigured`).
- Gate the sync-blocked branch on `accountSignedIn` so it no longer
  hijacks the manual-bridge discovery path.

Adds tests covering manual-bridge discovery and discovery-failure while
signed out. See docs/cases/manual-bridge-login-state/README.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* security(docs): remove plaintext review credentials, inject from .env

The svc.plus review password and the two bridge tokens were committed in
plaintext across the manual case / API test docs. Replace every value
with a `.env` / secret-store reference and add a tracked .env.example
template. Harden .gitignore (.env.*, *.local.env, secrets.env) while
keeping !.env.example.

Note: git history was rewritten separately to purge the leaked values;
the credentials must be rotated regardless.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(security): add gitleaks config allowlisting vendored/test fixtures

Suppress false positives so `gitleaks detect` is clean:
- third_party/* (cargokit ships a public binary-verification key)
- workspace_management_unit_test.dart (obfuscated "token" fixture)
- gatewayruntime/runtime_test.go (hardcoded "device-1" test key pair)

Real leaked secrets are purged from history, not allowlisted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(assistant): keep manual bridge usable when signed out of svc.plus

The gateway connection resolver short-circuited to "请先登录 svc.plus"
whenever the account was signed out, before checking whether a manual
bridge was configured or whether capability discovery was still running.
A saved manual bridge could therefore never be used while signed out.

- Only emit the signed-out prompt when neither an account session nor a
  manual bridge is configured (`!accountSignedIn && !bridgeConfigured`).
- Gate the sync-blocked branch on `accountSignedIn` so it no longer
  hijacks the manual-bridge discovery path.

Adds tests covering manual-bridge discovery and discovery-failure while
signed out. See docs/cases/manual-bridge-login-state/README.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(security): remove historical secret fixtures

* ci(release): load Vault secrets per-platform in build matrix

The build matrix loaded all 17 signing secrets in one shared block for
every platform. vault-action's ignoreNotFound only suppresses path-level
404s, not field-level "No match data" errors, so a single missing field
(e.g. APPLE_MAC_PROVISION_PROFILE_BASE64) failed every leg — including
linux/windows/android that need no Apple secrets.

Split the load into per-OS-family steps gated by matrix.platform:
- Apple (macos/ios): Apple cert + provisioning + keychain + export method
- Windows: WINDOWS_PFX_* + codesign subject
- Android: ANDROID_KEYSTORE_* + key alias/password
Linux requests nothing.

Also drop APP_STORE_CONNECT_* from the build matrix: only
testflight_upload.sh consumes them and it runs in the release job, which
loads them itself. The build matrix no longer depends on them.

Add shell: bash to the Export step (its `{ … } >> $GITHUB_ENV` brace
syntax is bash-only and would fail under the default pwsh on windows).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci: load Vault secrets per-platform in build matrix (#43)

The build matrix loaded every signing secret in one shared block for all
platforms. vault-action's ignoreNotFound only suppresses path-level 404s,
not field-level "No match data" errors, so a single missing field failed
every leg — including linux/windows/android that need no Apple secrets.

Split the load into per-OS-family steps gated by matrix.platform (Apple
for macos/ios, Windows, Android); linux requests nothing. Add shell: bash
to the Export step (its `{ … } >> $GITHUB_ENV` brace syntax is bash-only
and would fail under the default pwsh on windows).

Co-authored-by: Haitao Pan <manbuzhe2009@qq.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* feat: add one-line XWorkmate installer (#42)

Co-authored-by: Haitao Pan <manbuzhe2009@qq.com>

---------

Co-authored-by: Haitao Pan <haitao.pan@xworkmate.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Haitao Pan <manbuzhe2009@qq.com>
Co-authored-by: Cowork 3P <cowork-3p@localhost>
2026-06-29 15:58:04 +08:00

16 KiB
Raw Permalink Blame History

APP 对接外部服务 API 接口测试详细清单

Last Updated: 2026-04-22

本文记录 xworkmate-app 当前对外部服务的 APP 侧接口对接清单,重点覆盖:

  • 账户服务 accounts.svc.plus
  • 桥接服务 xworkmate-bridge.svc.plus
  • 桥接侧 JSON-RPC 会话接口 session.start / session.message / session.cancel / session.close

本文目标不是抽象协议说明,而是把 APP 真实会调用的接口、请求体、返回体、鉴权方式、已验证结果和当前风险点整理成可执行测试清单。

1. 范围与用途

1.1 涵盖范围

  • 账户登录与会话查询
  • 账户同步返回的 bridge 元数据
  • bridge 主入口 /acp/rpc
  • acp.capabilities
  • xworkmate.routing.resolve
  • 会话生命周期接口:
    • session.start
    • session.message
    • session.cancel
    • session.close

1.2 不涵盖范围

  • UI 视觉样式
  • 纯本地文件系统工具
  • 账户注册、找回密码、管理后台页面
  • bridge 后端内部 /acp-server/* / /gateway/* 私有映射细节

1.3 适用场景

  • Apple 审核只读账号连通性确认
  • APP 上线前外部依赖冒烟
  • bridge 协议改动后的回归核验
  • 安全边界确认:
    • BRIDGE_AUTH_TOKEN 是否只作为 Bearer token 使用
    • BRIDGE_SERVER_URL 是否仅作为元数据
    • 会话接口是否按当前 bridge contract 统一选择 /acp/rpc,并用 routing metadata 表达 OpenClaw gateway 目标

2. 统一测试前提

2.1 环境变量 / 外部参数

  • BRIDGE_SERVER_URL=https://xworkmate-bridge.svc.plus
  • BRIDGE_AUTH_TOKEN=<managed bridge token>

2.2 账户信息

  • url: https://accounts.svc.plus
  • login_name: review@svc.plus
  • login_password: 从 .env / secret store 注入 REVIEW_ACCOUNT_LOGIN_PASSWORD(勿写明文)

2.3 鉴权规则

  • 账户接口使用账户登录返回的 session token
  • bridge 接口使用 Authorization: Bearer <BRIDGE_AUTH_TOKEN>
  • 不允许用 gateway profile token 代替 bridge token
  • 不允许把 BRIDGE_SERVER_URL 当作 runtime 入口真源

2.4 当前代码侧入口

3. 接口总览

服务 方法 / 路径 HTTP 方法 鉴权 当前用途 备注
accounts /api/auth/login POST 登录并拿 session token Apple 审核只读账号使用
accounts /api/auth/session GET Authorization: Bearer <session token> 获取当前会话和用户信息 APP 端登录态校验
accounts /api/auth/xworkmate/profile/sync GET Authorization: Bearer <session token> 拉取 bridge 同步元数据 返回 BRIDGE_SERVER_URL / BRIDGE_AUTH_TOKEN
bridge /acp/rpc POST Authorization: Bearer <BRIDGE_AUTH_TOKEN> bridge JSON-RPC 主入口 capabilities、routing、agent 任务、OpenClaw gateway 任务、cancel、close
bridge acp.capabilities JSON-RPC method 同上 拉取 provider catalog / target catalog capability 只读快照
bridge xworkmate.routing.resolve JSON-RPC method 同上 解析 provider / gateway / skills 路由 返回 resolved / unavailable 信息
bridge session.start JSON-RPC method 同上 开启新会话 session 生命周期起点
bridge session.message JSON-RPC method 同上 继续现有会话 续写 / follow-up
bridge session.cancel JSON-RPC method 同上 取消正在进行的会话 终止流式任务
bridge session.close JSON-RPC method 同上 关闭会话 释放会话资源

4. 账户服务测试清单

4.1 POST /api/auth/login

目标

  • 验证只读审核账号可以正常登录
  • 验证账户服务返回 session token

请求

{
  "identifier": "review@svc.plus",
  "password": "${REVIEW_ACCOUNT_LOGIN_PASSWORD}"
}

期望返回

  • HTTP 200
  • 响应体包含:
    • access_token
    • token
    • expiresAt
    • user
    • mfaRequired / mfa_required

当前实测结果

  • 已通过
  • 返回 200
  • 返回体包含用户 readonly 角色与会话 token

关键断言

  • 不应返回 MFA 挑战
  • 不应要求额外二次登录
  • token 不应写入普通 settings

4.2 GET /api/auth/session

目标

  • 校验登录 token 是否可用于读取当前会话
  • 校验用户信息、角色、权限是否可见

请求

  • Header: Authorization: Bearer <session token>

期望返回

  • HTTP 200
  • user.email
  • user.username
  • user.role
  • user.permissions
  • user.tenants 或等价租户信息

当前实测结果

  • 已通过
  • 返回 200
  • 能读取会话和权限

关键断言

  • 不能依赖 bridge token
  • 不能读取旧的 managed secret 代替 session token

4.3 GET /api/auth/xworkmate/profile/sync

目标

  • 读取 bridge 同步元数据
  • 确认 APP 只把 BRIDGE_SERVER_URL 作为 metadata
  • 确认 BRIDGE_AUTH_TOKEN 能被同步回 APP 侧 secure storage

请求

  • Header: Authorization: Bearer <session token>

期望返回

  • HTTP 200
  • 响应体包含:
    • BRIDGE_SERVER_URL
    • BRIDGE_AUTH_TOKEN

当前实测结果

  • 已通过
  • 返回:
    • BRIDGE_SERVER_URL=https://xworkmate-bridge.svc.plus
    • BRIDGE_AUTH_TOKEN=<managed bridge token>

关键断言

  • BRIDGE_SERVER_URL 只作为同步元数据,不参与 runtime endpoint 选择
  • BRIDGE_AUTH_TOKEN 只进入 secure storage / managed secret

5. 桥接主入口测试清单

5.1 POST /acp/rpc

目标

  • 验证 bridge 主入口可连通
  • 验证鉴权头正确
  • 验证 JSON-RPC 协议错误返回格式

请求

  • Header: Authorization: Bearer <BRIDGE_AUTH_TOKEN>
  • Header: Content-Type: application/json
  • Body: JSON-RPC payload

期望返回

  • HTTP 200 或 JSON-RPC 协议级错误
  • 响应体为 JSON-RPC 风格:
    • jsonrpc
    • id
    • ok
    • result
    • error

当前实测结果

  • 发送空对象会返回协议错误:
    • missing method
  • 说明服务在线,入口正确

关键断言

  • 不应走 /acp-server/*
  • 不应走 /gateway/*
  • 不应回退到本地 loopback 作为 runtime 主入口

5.2 acp.capabilities

请求体

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "acp.capabilities",
  "params": {}
}

返回体重点

  • availableExecutionTargets
  • providerCatalog
  • gatewayProviders
  • singleAgent
  • capabilities

当前实测结果

  • availableExecutionTargets: agent, gateway
  • providerCatalog:
    • codex
    • opencode
    • gemini
    • hermes
  • gatewayProviders:
    • openclaw

关键断言

  • providerCatalog 只作为 agent 目标 catalog
  • gatewayProviders 只作为 gateway 目标 catalog
  • APP 侧 provider 菜单必须来自这里,不可静态硬编码

5.3 xworkmate.routing.resolve

请求体

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "xworkmate.routing.resolve",
  "params": {
    "taskPrompt": "check api",
    "workingDirectory": "/tmp",
    "routing": {
      "routingMode": "auto",
      "preferredGatewayTarget": "codex",
      "explicitExecutionTarget": "agent",
      "explicitProviderId": "codex",
      "explicitModel": "",
      "explicitSkills": [],
      "allowSkillInstall": false,
      "availableSkills": []
    }
  }
}

返回体重点

  • resolvedExecutionTarget
  • resolvedProviderId
  • resolvedGatewayProviderId
  • resolvedModel
  • resolvedSkills
  • unavailable
  • unavailableCode
  • unavailableMessage

当前实测结果

  • resolvedExecutionTarget: single-agent
  • resolvedProviderId: codex
  • unavailable: false

关键断言

  • 路由解析结果必须和 UI / controller 的执行目标一致
  • unavailable 为真时必须能带出原因字段

6. 会话接口测试清单

6.1 通用请求模型

桥接侧会话接口都使用 JSON-RPC且共享同一套会话标识

  • sessionId
  • threadId
  • 任务类请求还会带:
    • mode
    • taskPrompt
    • workingDirectory
    • selectedSkills
    • attachments
    • provider
    • routing
    • requestedExecutionTarget
    • executionTarget

这些字段由 GoTaskServiceRequest.toExternalAcpParams() 生成。

6.2 session.start

目标

  • 开启新任务会话
  • 验证桥接会话起点是否正确走向下游执行面

最小请求体

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "session.start",
  "params": {
    "sessionId": "test-session-001",
    "threadId": "test-session-001",
    "mode": "gateway-chat",
    "taskPrompt": "Say hello in one short sentence.",
    "workingDirectory": "/tmp",
    "selectedSkills": [],
    "attachments": [],
    "provider": "codex",
    "routing": {
      "routingMode": "auto",
      "preferredGatewayTarget": "codex",
      "explicitExecutionTarget": "agent",
      "explicitProviderId": "codex",
      "explicitModel": "",
      "explicitSkills": [],
      "allowSkillInstall": false,
      "availableSkills": []
    },
    "requestedExecutionTarget": "agent",
    "executionTarget": "agent"
  }
}

返回体重点

  • ok
  • success
  • error
  • mode
  • provider
  • resolvedExecutionTarget
  • resolvedProviderId
  • resolvedGatewayProviderId
  • resolvedModel
  • resolvedSkills
  • skillResolutionSource
  • needsSkillInstall
  • turnId
  • unavailable

当前实测结果

  • HTTP 200
  • 返回 success: false
  • 返回错误:
    • dial tcp 127.0.0.1:9001: connect: connection refused
  • 返回 resolvedExecutionTarget: single-agent
  • 返回 resolvedProviderId: codex
  • 返回 turnId

结论

  • 协议入口正常
  • 会话方法可用
  • 当前失败点在桥接后端继续转发到本地 127.0.0.1:9001

关键断言

  • 不能回退到本地 hardcoded endpoint 作为 APP runtime 真源
  • 不能把 provider 路由走成 /acp-server/* 直连

6.3 session.message

目标

  • 继续已有会话
  • 校验 follow-up 是否沿用同一 sessionId / threadId

最小请求体

{
  "jsonrpc": "2.0",
  "id": "2",
  "method": "session.message",
  "params": {
    "sessionId": "test-session-001",
    "threadId": "test-session-001",
    "mode": "gateway-chat",
    "taskPrompt": "Continue with a very short acknowledgement.",
    "workingDirectory": "/tmp",
    "selectedSkills": [],
    "attachments": [],
    "provider": "codex",
    "routing": {
      "routingMode": "auto",
      "preferredGatewayTarget": "codex",
      "explicitExecutionTarget": "agent",
      "explicitProviderId": "codex",
      "explicitModel": "",
      "explicitSkills": [],
      "allowSkillInstall": false,
      "availableSkills": []
    },
    "requestedExecutionTarget": "agent",
    "executionTarget": "agent"
  }
}

返回体重点

  • session.start 相同的会话结果字段

当前实测结果

  • HTTP 200
  • 返回 success: false
  • 返回错误:
    • dial tcp 127.0.0.1:9001: connect: connection refused
  • 返回 turnId

关键断言

  • 续写请求不能改写线程归属
  • 续写请求不能偷偷切换到另一个 provider

6.4 session.cancel

目标

  • 取消进行中的会话
  • 校验取消接口是否幂等可用

最小请求体

{
  "jsonrpc": "2.0",
  "id": "3",
  "method": "session.cancel",
  "params": {
    "sessionId": "test-session-001",
    "threadId": "test-session-001"
  }
}

返回体重点

  • accepted
  • cancelled

当前实测结果

  • HTTP 200
  • 返回:
    • accepted: true
    • cancelled: false

关键断言

  • 取消接口应可在会话失败后调用
  • 不应因会话已失败而返回协议错误

6.5 session.close

目标

  • 关闭会话
  • 回收会话资源

最小请求体

{
  "jsonrpc": "2.0",
  "id": "4",
  "method": "session.close",
  "params": {
    "sessionId": "test-session-001",
    "threadId": "test-session-001"
  }
}

返回体重点

  • accepted
  • closed

当前实测结果

  • HTTP 200
  • 返回:
    • accepted: true
    • closed: true

关键断言

  • 会话关闭应始终可调用
  • 关闭接口不能依赖会话先成功完成

7. 代码到接口的映射

代码位置 说明
lib/runtime/account_runtime_client.dart 账户登录、会话、同步接口封装
lib/runtime/gateway_acp_client.dart bridge JSON-RPC 请求、capabilities、routing、session 生命周期
lib/runtime/go_task_service_client.dart 会话请求参数组装
lib/runtime/external_code_agent_acp_desktop_transport.dart session.start / session.message 触发路径

8. 自动化测试建议

8.1 现有自动化基础

8.2 推荐新增测试

桥接协议层

  • test/runtime/gateway_acp_client_session_test.dart
    • 覆盖 session.start
    • 覆盖 session.message
    • 覆盖 session.cancel
    • 覆盖 session.close
    • 断言 Bearer 头、JSON-RPC method、params 结构

失败分支

  • session.start 下游连接失败时,返回值中应保留:
    • success: false
    • error
    • turnId
    • resolvedProviderId
  • session.message follow-up 失败时,不应破坏会话标识

8.3 建议断言

  • Authorization 必须是 Bearer <token>
  • capability、routing、agent 任务、OpenClaw gateway session.start / session.messagesession.cancelsession.close 请求路径必须是 /acp/rpc
  • 不允许出现 /acp-server/ 直连请求
  • 不允许出现 /gateway/openclaw app-facing 请求OpenClaw gateway 目标必须通过 routing metadata 表达
  • session.cancel / session.close 必须接受 sessionId + threadId
  • BRIDGE_SERVER_URL 不可参与运行时路径拼接

9. 当前已知风险

  • session.start / session.message 当前环境下下游连接到 127.0.0.1:9001 失败
  • 这说明 bridge 主入口可用,但后端 provider 适配层在当前运行环境里未就绪
  • 这是 bridge 后端运行态问题,不是 APP 侧 JSON-RPC 协议错误

10. 执行顺序建议

  1. POST /api/auth/login
  2. GET /api/auth/session
  3. GET /api/auth/xworkmate/profile/sync
  4. acp.capabilities
  5. xworkmate.routing.resolve
  6. session.start
  7. session.message
  8. session.cancel
  9. session.close

11. 结论

当前 APP 对接外部服务的主链路已经明确:

  • 账户侧负责登录与同步元数据
  • bridge 侧负责 capability、路由解析和会话生命周期
  • capability、routing、agent 任务、OpenClaw gateway 任务、cancel、close 经过 /acp/rpc
  • OpenClaw session.start / session.message 通过 /acp/rpc routing metadata 表达 gateway/openclaw 目标
  • session.cancel / session.close 的协议入口已验证可用
  • 当前剩余风险集中在桥接后端下游 provider 连接,而不是 APP 侧接口拼接