opensymphony 3.0.0

A Rust implementation of the OpenAI Symphony orchestration design
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
# Testing

This document defines the test strategy for OpenSymphony. For local operating
procedures, doctor guidance, rehydration, diagnostics, packaging, and safety
notes, see [operations.md](operations.md).

## 1. Testing philosophy

OpenSymphony sits at the intersection of:

- a specification-driven orchestrator
- an external issue tracker
- a remote-style agent runtime
- a terminal UI

The project needs more than unit tests. It needs layered validation with deterministic fakes and opt-in live tests.

Projection tests must cover round trips, blocked-state rendering, local versus
remote path boundaries, and secret-canary absence across Rust, TypeScript, TUI,
web, and desktop surfaces.

## 2. Test layers

## 2.1 Unit tests

Every internal subsystem module should have focused unit tests for pure logic.

Examples:

- workflow parsing and strict template rendering
- issue identifier sanitization
- config resolution and environment indirection
- retry delay math
- event ordering and deduplication
- snapshot reducers
- TUI reducers and formatting helpers

## 2.2 Contract tests

Use the internal `opensymphony_testkit` module for protocol-level checks
against stable fixtures.

Required contract suites:

- conversation create payload serialization
- user-message event payload serialization
- `run` trigger request behavior
- WebSocket event decoding for known event types
- unknown-event pass-through handling
- event-search pagination and reconciliation
- terminal state derivation from `ConversationStateUpdateEvent`

## 2.3 Integration tests with fakes

Run these in CI.

Components to fake:

- OpenHands agent-server
- Linear GraphQL responses
- local control-plane API consumer

Why fakes matter:

- deterministic edge-case coverage
- out-of-order event sequences
- disconnect and reconnect behavior
- server restart scenarios
- scheduler recovery on daemon restart
- parent integration launch-intent persistence before worker start, exact
  run-bound final-verification receipts, missing/stale receipt rejection,
  exact command hashing before durable redaction, prior-attempt event rejection,
  production-shaped Codex and OpenHands command start/completion events,
  observed parent-root and checkout working directories, orchestrator-owned
  deadlines, bounded command logs/resources, rejection of prompt-authored
  execution claims, uncertain cleanup fences, metadata-only prelaunch crash
  recovery, authenticated same-conversation parent grants after restart,
  prelaunch rejection of missing or changed bound conversation manifests and
  parent harness switches, attempt-specific continuation prompts for Codex and
  OpenHands, terminal-turn cleanup before retry, retryable active cancellation,
  completed-parent reopen with unchanged child edges, compacted admission
  idempotency, empty-target verification, recursive intermediate-descendant
  memory grants, durable-controller-gated parent capture, stable default memory
  endpoint recovery, event-only command-receipt persistence, dry-run preview
  isolation, legacy missing-controller migration before same-conversation
  reattachment, terminal-success finalization gates, and retry after a failed
  durable outcome write
- parent repair branch, push, pull-request, review, merge, and refresh
  reconciliation with side-effect counters; persistence failure before branch
  creation; bounded current-head feedback for credential-scrubbed workers;
  resolved-thread pushback; controller cancellation between repair turns and
  when tracker state changes before a completed implementation turn publishes;
  retention after a conversation-bound transport failure without terminal proof;
  requested changes on one PR; failed checks, rejection, outage,
  external closure, force-push, and conflict states; squash/rebase merge-result
  reachability; retained-child reachability after target refresh; inherited
  commit-signing isolation; and separately auditable attempts across repositories

## 2.4 Live local tests

These are opt-in and run against a pinned real OpenHands server on a trusted machine.

Gate them behind explicit environment variables.

Suggested gates:

- `OPENSYMPHONY_LIVE_OPENHANDS=1`
- `OPENSYMPHONY_LIVE_LINEAR=1`

Current implementation:

- the repository, CI, Clippy MSRV checks, root package, and desktop package all
  use Rust 1.97.1; the Edition 2024 workspace uses Cargo Resolver 3
- `cargo check-dev`, `cargo test-dev`, and `cargo clippy-dev` are repository
  aliases for iterative OpenSymphony development. The aliases set
  `DUCKDB_DOWNLOAD_LIB=1` only for the aliased command and build with
  `--no-default-features --features duckdb-prebuilt` so the native DuckDB
  library is downloaded into
  `target/duckdb-download` and reused across rebuilds in the same target
  directory.
- `cargo test` exercises the full root package, including the fake-server contract suite from `tests/fake_server_contract.rs`
- `cargo test --test linear_client` exercises fixture-backed GraphQL normalization, parent/child hierarchy extraction, personal-API-key auth headers, required API-key/project/state configuration validation, issue URL/raw-priority preservation, full label pagination, raw workflow-state type preservation alongside normalized kinds, non-archived candidate polling, lightweight dispatch-summary reads, archived terminal cleanup reads, archived by-ID state refresh, GraphQL 400/429 rate-limit retries including reset-header handling, long rate-limit reset return-without-sleep behavior with the 30s inline cap, retryable 5xx GraphQL error envelopes, project-scoped by-ID state refresh with bounded unscoped fallback for moved issues, and tracker error mapping against a local stub server
- `cargo test --test linear_client live_linear_client_reads_opensymphony_project -- --ignored --nocapture` is a read-only live evidence probe for PRs that need to show the actual Linear HTTP/GraphQL client path against the OpenSymphony project
- `cargo test --test hierarchy_selection --test scheduler` exercises blocker-aware and hierarchy-aware dispatch filtering, child-edge generation reconciliation and freeze fencing, owner-identified lease acquisition, provider-evidence parent eligibility, leaf-before-parent ordering, cached per-state capacity limiting, continuation retry, exponential failure backoff, runtime-event-fed stall detection, terminal cleanup/release, active-state reconciliation, Linear cooldown behavior, separated Linear polling cadences, manifest-backed workspace recovery against fake tracker/workspace/worker backends, external retry-marker proof, metadata-only workspace recovery, binding-drift workspace rematerialization, legacy parent neutrality, same-ID generation retention, independent running/discovery cadences, and adoption of every launched worker after persistence errors
- `cargo test --lib parent_integration` exercises the restart-safe parent state machine, exact multi-repository and empty-target evidence, topology-neutral checkout handles, idempotent admission after transition compaction, bounded diagnostics, timeout and indeterminate cleanup gates, resource collisions, and higher-ancestor serialization
- the memory scope and terminal capture tests cover parent grants across exact descendants, denial of unrelated repositories and work items, parent runtime-envelope capture, and preservation of every verified repository commit
- `cargo test --lib orchestrator_run::backends::tests` covers runtime workspace-manifest recovery, in-flight run detection from `run.json`, and launch-path failure handling in the concrete CLI adapter
- `cargo test --test workspace_manager` covers durable checkout/staging ownership-marker sweeps, preservation of foreign generation-shaped directories and staging content, receipt-owned recovery, and the retry verification mode that permits legitimate worker changes while retaining checkout provenance checks
- `cargo test --lib opensymphony_workspace::manager::tests::discover_agents` and the memory scope tests cover bounded tracked-instruction probes, failure propagation, canonical project-ID filtering, and project-scoped direct capsule reads
- `scripts/hermetic_multi_repo_lifecycle.sh` is the M12.97 release gate. It
  composes the inherited strict-config, migration/rollback, three-bare-repository
  workspace, scheduler/provider restart, memory-scope, gateway/TUI, and
  web/desktop suites and writes exact commit/config-hash evidence. The numbered
  boundary and fault mapping lives in `docs/multi-repository-rollout.md`.
- `cargo test --lib orchestrator_run::backends::tests` covers deferred cross-harness retirement so a failed replacement keeps the previous session recoverable
- `tests/doctor.rs` runs the CLI live-probe path against the internal `opensymphony_testkit` module
- `scripts/smoke_local.sh` runs the static doctor pass
- `scripts/live_e2e.sh` gates the live doctor run behind `OPENSYMPHONY_LIVE_OPENHANDS=1`
- `tests/fake_server_contract.rs` and `tests/client_resilience.rs` now split the runtime stream coverage intentionally: the shared fake-server contract suite owns the scripted initial snapshot replay, attach-backlog versus buffered-live ordering, reconnect exhaustion, explicit-close shutdown semantics, reconcile, out-of-order delivery, and reconnect recovery cases, while `client_resilience.rs` keeps the narrower auth, forward-compatibility, and mirror-regression cases that still need bespoke server behavior
- `tests/live_pinned_server.rs` provides an opt-in live integration check against the pinned `openhands-agent-server==1.24.0` surface for external-mode auth success and failure
- `tests/issue_session_runner.rs` now covers continuation reuse, already-running conversation wait/retry behavior, launch reporting for reused running conversations before prior-turn drain completes, delayed `/run` conflicts that surface an active prior turn only after attach, missing-conversation recreation that stays on continuation guidance, **simplified conversation resumption that reuses conversations as-is without LLM config drift checks**, configured `persistence_dir_relative` handling, terminal-error normalization, and temp-repo smoke execution
- `tests/supervisor.rs` now covers startup rejection when a foreign ready server is already bound to the supervised target port
- `tests/update.rs` covers the new `opensymphony update` maintenance flow: skipping `cargo install opensymphony --locked` when the running CLI already matches the newest published release, running the locked install when a newer release exists, refreshing template-managed skill files in place for an existing target repo, and skipping that skill refresh outside a repo that lacks `WORKFLOW.md` plus `config.yaml`
- `tests/memory.rs` covers the first memory workflow: capture dry runs, capsule writes, DuckDB indexing, compact briefs, search, docs-sync dry-run diffs, public/private link handling, OKF lint fixture diagnostics, OKF MCP admin payloads, date-grouped generated memory logs, and Linear archive eligibility gating
- `opensymphony-gateway-schema/tests/gateway_schema.rs` and
  `opensymphony-gateway/tests/gateway.rs` cover Codex local readiness rendering
  with fake command outputs for installed, logged-out, unsupported, and
  permission-denied states. These tests assert that the gateway exposes only
  safe status metadata and `codex_cli_login` references, never raw OAuth access
  or refresh material.

Focused OKF memory validation for implementation work:

- `cargo test-system-duckdb okf_lint_fixture_reports_errors_warnings_and_info`
  verifies OKF lint errors, warnings, info diagnostics, and metadata
  preservation for the migration fixture corpus.
- `cargo test-system-duckdb --test memory` runs the CLI-facing OKF fixture test,
  MCP `memory.lint` argument coverage for `okf` and `bundleRoot`, generated
  `log.md` date grouping, OKF import/export redaction checks, import preflight
  failure coverage, documented non-transactional mid-copy import behavior,
  source/target overlap rejection, and the rest of the memory integration
  suite.
- `opensymphony memory lint --okf <repo-contained-bundle>` is the manual CLI
  smoke path for a generated or fixture OKF bundle.
- `opensymphony memory export-okf --visibility public --output <empty-dir>`
  followed by `opensymphony memory lint --okf --public-docs <empty-dir>` is the
  public export redaction smoke path.
- `opensymphony memory import-okf <repo-contained-bundle>` is the import smoke
  path for warning-tolerant OKF bundles with actionable malformed-file errors,
  repository-contained sources, non-overlapping targets, and preflighted writes.
  The documented post-preflight partial-write regression is Unix-gated because
  it uses POSIX directory permissions to induce a deterministic mid-copy write
  failure; add a separate Windows-native failure injection before treating that
  path as covered on Windows.

Codex ChatGPT subscription smoke testing remains opt-in on trusted local
machines because the final exec probe can consume account quota. The supported
operator sequence is:

```bash
codex --version
codex app-server --help
codex login status
codex --ask-for-approval never exec --sandbox read-only \
  "Reply with exactly: CODEX_LOGIN_OK"
```

If login is missing or expired, use `codex login --device-auth`; if the account
has not enabled device-code authorization, enable ChatGPT Settings -> Security
and login -> Enable device code authorization for Codex before retrying.

## 3. Minimum required test coverage by subsystem

## 3.1 Workflow and config

- parse valid `WORKFLOW.md`
- parse the checked-in repository and example `WORKFLOW.md` files
- fail on invalid front matter
- fail on unknown top-level workflow namespaces
- fail on unknown template variables
- resolve defaults and env vars
- fail when an explicitly referenced env token such as `tracker.api_key: $VAR` is unset
- fall back to `LINEAR_API_KEY` when `tracker.api_key` is omitted
- fail when `tracker.active_states` or `tracker.terminal_states` are omitted
- resolve workflow-relative workspace paths and relative OpenHands persistence paths
- resolve bare relative workspace roots against the `WORKFLOW.md` directory
- normalize relative workflow directories first so relative `workspace.root` values still resolve to absolute paths
- reject parent-directory traversal in relative OpenHands persistence paths
- validate `openhands` extension namespace
- leave `openhands.local_server.command` unset when omitted so the runtime-owned local tooling layer resolves the pinned launcher from the OpenSymphony checkout
- resolve `openhands.local_server.command` during workflow loading and honor it only for daemon-managed local supervision
- fail at runtime when `openhands.local_server.command` is configured for external, authenticated, or `local_server.enabled: false` targets
- fail when `openhands.local_server.enabled: false` is configured until the runtime supervisor can honor workflow-owned local-server disablement instead of still deciding launch behavior from the localhost base URL plus pinned tooling readiness
- fail when `openhands.local_server.env` is configured until the runtime supervisor creation path forwards workflow-owned launcher environment variables instead of always using runtime-owned defaults
- fail when `openhands.local_server.readiness_probe_path` is configured until the runtime supervisor launch path consumes workflow-owned probe settings instead of always using `/openapi.json`
- fail when `openhands.local_server.startup_timeout_ms` is configured until the runtime supervisor creation path consumes workflow-owned startup timeout settings instead of always using the supervisor default
- resolve the bundled `examples/target-repo/WORKFLOW.md` file end-to-end, not just parse it
- treat a leading unmatched `---` as prompt body text instead of failing front-matter parsing
- treat leading thematic-break-delimited non-mapping blocks as prompt body text instead of silently dropping prompt content
- fail on malformed, non-`http://`/`https://`, credential-bearing, query-bearing, fragment-bearing, or bracketed-IPv6 `openhands.transport.base_url` values during workflow resolution
- allow `https://` and path-prefixed OpenHands transport base URLs during workflow resolution
- fail when a non-loopback OpenHands transport base URL uses `http://`
- fail when a non-loopback OpenHands transport base URL omits `openhands.transport.session_api_key_env`
- resolve `openhands.transport.session_api_key_env`, `openhands.websocket.auth_mode`, and `openhands.websocket.query_param_name` into the runtime transport config
- normalize unauthenticated path-prefixed loopback OpenHands transport base URLs back to their origin before managed local supervisor startup while preserving configured prefixes for external or authenticated targets
- fail when `openhands.websocket.auth_mode` is invalid or requires a missing session API key env
- fail when explicit `openhands.websocket.enabled` is configured before the runtime readiness path can honor disabling the socket
- resolve `openhands.websocket.ready_timeout_ms`, `reconnect_initial_ms`, and `reconnect_max_ms` into the runtime readiness and reconnect budgets
- reject removed `openhands.mcp` config with a migration error that points users to `LINEAR_API_KEY` and the repo-local GraphQL helper assets
- resolve `openhands.conversation.reuse_policy` for runtime consumers instead of rejecting non-default values during workflow loading
- default required OpenHands conversation request fields such as `confirmation_policy` and `agent`, including `confirmation_policy.kind` when the block is present without an explicit kind
- fail when `openhands.conversation.confirmation_policy` includes options that cannot be represented in the current OpenHands request subset
- fail when `openhands.conversation.max_iterations` exceeds the downstream OpenHands `u32` request range
- fail when `openhands.conversation.agent.log_completions` or extra agent option keys are configured before the runtime conversation-create adapter can forward them
- fail when `openhands.conversation.agent.llm` is present without a non-empty `model`
- fail when `openhands.conversation.agent.llm` includes extra option keys before the runtime conversation-create adapter can forward them
- resolve `openhands.conversation.agent.llm.api_key_env` and `base_url_env` into the conversation-create payload at runtime
- fail when configured `openhands.conversation.agent.llm.api_key_env` or `base_url_env` names are missing or blank in the runtime environment
- fail on malformed `agent.max_concurrent_agents_by_state` entries
- preserve the Markdown body exactly after the front matter terminator
- treat whitespace-only prompt bodies as absent so `DEFAULT_PROMPT_TEMPLATE` still applies

## 3.1.1 Code Graph repository indexing

- exercise the empty-DuckDB gateway flow: repository discovery, target-branch
  index, accepted/progress/completed events, nonempty snapshot, baseline
  `code.graph.context`, dirty workspace overlay, and cleanup
- verify a dirty cross-module call produces an added edge and module-connection
  delta against the configured target branch
- assert the fixture, production HTTP, and Tauri-native adapters return the same
  index-report and graph DTO shapes
- bootstrap an empty DuckDB index from the configured target branch and assert
  nonzero documents, symbols, and edges for supported source
- keep base and later commits independently queryable, including identical
  content hashes
- re-index a changed and deleted path incrementally and verify deletion/stale
  membership plus skipped-directory, unsupported-language, and size coverage
- verify target-branch selection when `develop` and `main` point to different
  commits; reject client filesystem roots and never execute target-repository
  code
- serialize concurrent index requests through one writer and keep reads
  available during a background job
- cover gateway and native-command parity for accepted, progress, completed,
  unavailable, and failed reports/events

## 3.2 Workspace manager

- sanitize issue identifiers
- refuse path escape
- create and reuse workspace
- persist issue and run manifests
- persist conversation manifests
- persist stable prompt captures plus per-run prompt archives
- persist generated `issue-context.md` and `session-context.json`
- allow fresh `after_create` hooks to bootstrap clone/worktree flows before `.opensymphony/` exists
- retry failed first-time `after_create` hooks on the next `ensure`
- remember a successful first-time `after_create` before later metadata bootstrap steps so clone/worktree hooks are not rerun after a post-hook bootstrap failure
- reject sanitized-key collisions when an existing current-path issue manifest belongs to another issue
- ignore foreign, copied, or undecodable `.opensymphony/issue.json` artifacts when deciding whether first bootstrap already completed
- hook timeout
- kill spawned hook descendants when a timeout fires
- hook stderr capture
- avoid login-shell startup files when launching Unix hooks
- reject symlinked workspace roots during reused-workspace validation
- reject symlink-based `cwd` escapes for hooks
- reject symlinked `.opensymphony` manifest reads and writes
- cleanup on terminal issue state
- revoke worker memory grants at terminal, inactive, and binding-supersession
  boundaries

## 3.3 OpenHands adapter

- supervised server startup and shutdown
- HTTP client auth modes
- external server path-prefix probes
- conversation creation
- initial REST sync
- WebSocket readiness barrier
- post-ready reconcile
- reconnect with backoff
- out-of-order event insertion
- terminal state detection
- conversation reuse for `per_issue`
- `fresh_each_run` reset/new-conversation behavior
- runtime rejection of unsupported reuse-policy values
- persisted policy-drift resets
- recovered trigger-pending `/run` retry after a `409 Conflict`
- recovered `409 Conflict` baseline refresh after the previous turn drains
- preservation of untrusted superseded conversations without remote retirement
- condenser replacement evidence persistence and post-retirement clearing
- identifier-derived workspace-key supersession for same-ID tracker changes
- same-harness Codex supersession evidence and harness-specific persistence paths
- prepared Codex recovery without a persisted turn id resumes with `turn/start`
- pinned-server auth success and failure paths
- reuse after an already-active turn or `/run` conflict
- recreation of a missing conversation with persisted history
- **simplified conversation resumption without LLM config drift checks**
- workflow-owned `persistence_dir_relative` mapping
- supervised-mode rejection of foreign ready servers

## 3.4 Orchestrator

- poll candidate sorting
- blocker-aware and hierarchy-aware dispatch eligibility
- claim and release transitions
- max concurrency
- failure retry backoff
- continuation retry at fixed delay
- stall detection
- lightweight active-state refresh cadence
- Linear rate-limit cooldown that does not block worker updates
- terminal cleanup
- restart recovery from manifests

Current repository implementation:

- `tests/scheduler.rs` covers continuation retry, failure backoff, cached per-state dispatch limits across finish/stall/inactive/terminal/reconciliation transitions, runtime-event-fed stall detection, terminal reconciliation with cleanup, Linear read cooldown and cadence, lightweight running-state refresh, and manifest-backed workspace recovery using fake backends. Scheduler unit tests also cover the shorter full-detail refresh cadence for completed parent fan-in
- local restart validation should confirm that `opensymphony run` publishes a recovered snapshot before the first post-restart launch wave, so the TUI issue list repopulates even when reused conversations still take time to attach
- `crates/opensymphony-cli/src/orchestrator_run/backends.rs` covers immediate launch-failure cleanup and abort-on-drop cleanup for tracked runtime worker tasks in the production CLI adapter

## 3.5 Control plane and TUI

- snapshot derivation
- JSON serialization
- streaming update fanout
- read-only client invariants
- pane layout persistence
- event log rendering

Current implemented checks:

- snapshot serialization in `opensymphony-domain`
- parent/sub-issue tracker normalization and issue-ref terminal matching in `opensymphony-domain`
- forward-compatible snapshot decoding for unknown additive recent event kinds in `opensymphony-domain`
- forward-compatible snapshot decoding for unknown additive `daemon.state`, `runtime_state`, and `last_outcome` values in `opensymphony-control`
- control-plane HTTP plus SSE round-trip coverage in `opensymphony-control/tests/control_plane.rs`
- control-plane bootstrap snapshot timeout coverage in `opensymphony-control/tests/control_plane.rs`
- control-plane SSE connect-establishment timeout coverage in `opensymphony-control/tests/control_plane.rs`
- control-plane idle SSE timeout coverage in `opensymphony-control/tests/control_plane.rs`, including retry-in-place reconnect signaling
- control-plane post-disconnect reconnect-timeout reapplication coverage in `opensymphony-control/tests/control_plane.rs`
- control-plane monotonic lag-recovery coverage in `opensymphony-control/src/lib.rs`
- gateway compatibility coverage for `/healthz`, `/api/v1/snapshot`, `/api/v1/capabilities`, and `/api/v1/dashboard/snapshot` in `opensymphony-gateway/tests/gateway.rs`
- `opensymphony run` startup coverage that verifies the configured bind address exposes both health and gateway dashboard routes in `opensymphony-cli/tests/run.rs`
- workflow harness/model selection coverage in `opensymphony-workflow` unit
  tests, including `OPENSYMPHONY_HARNESS`, `OPENSYMPHONY_MODEL`, and
  `OPENSYMPHONY_MODEL_PROFILE` override resolution
- scheduler route decision coverage in `opensymphony-orchestrator/tests/scheduler.rs`
  for Codex selection, environment-sourced selection, and unavailable-harness
  failure
- Codex approval bridge coverage in `tests/codex_app_server.rs`, using fake
  JSON-RPC approval notifications to prove approval-center DTO mapping and
  approval decision audit records
- TUI reducer, visible-focus rendering, selection preservation across reorder, long-list selection windowing, narrow-layout detail budgeting, snapshot coalescing, stale snapshot rejection, post-restart snapshot reset recovery, disconnect retention, and reconnect-to-live recovery coverage in `opensymphony-tui`

## 3.6 Shared client shell (web and desktop remote)

The web and desktop clients both mount the shared `OpenSymphonyApp` shell from `@opensymphony/ui-core` against the same `GatewayTransport` interface, so remote parity is structural. Implemented checks:

- app-shell mount smoke (`packages/ui-core/__tests__/app-shell.test.ts`): status, task graph, run detail, evidence, profile, and failed-connection rendering
- auth-aware placeholder states (`packages/ui-core/__tests__/auth-states.test.ts`): unauthenticated (sign-in), unauthorized (access denied), forbidden (access forbidden), organization/project selection placeholders, and local `auth_modes:["none"]` gateways rendering the dashboard with no login gate; recovery when the gateway later permits a read
- remote web/desktop parity (`packages/ui-core/__tests__/remote-parity.test.ts`): the shell renders the same core dashboard metrics, task graph nodes, run detail, planning workspace, and stream events in both `mode:"web"` and `mode:"desktop"` against an identical fixture transport
- gateway error classification (`packages/api-client/__tests__/gateway-errors.test.ts`): `HttpGatewayTransport` maps HTTP 401/403 (including a 403 with an explicit `error_code:"unauthorized"` body signal) to a classified `GatewayRequestError`, and `authStateFromError` maps it to an `AuthState` from `@opensymphony/gateway-schema`

Code Graph UI validation also covers the real empty-state interaction: the
keyboard-accessible index button, disabled progress state, skipped-file
coverage, retry diagnostics, target-revision/provenance labels, stale and
truncated status, refresh after `code_graph_updated`, and recovery when an
accepted/progress job completes without event delivery. The packaged desktop
smoke must use production adapters; passing only `?fixtures` is insufficient.

Release-sensitive evidence for this surface includes:

```bash
cargo clippy-system-duckdb
npm run type-check
npm run package:release --workspace=@opensymphony/desktop -- --dry-run
```

Run the corresponding bundled-mode `cargo clippy --all-targets -- -D warnings`
and `cargo test` checks before publishing a release bundle.

### Evidence for UI/shell changes

The shell is pure DOM rendered by `renderOpenSymphonyApp` into a `jsdom` document, so the jest suites assert the rendered DOM directly (not mock return values). For the COE-419 auth placeholder states this means concrete runtime evidence of the rendered output:

- `data-opensymphony-app-shell="mounted"` root carries `data-auth-state` set to `unauthenticated` / `unauthorized` / `forbidden` / `open` for each scenario.
- `[data-testid="auth-placeholder"]` is present only in non-open states and carries the matching `data-auth-state`; `textContent` contains "Sign in required" (unauthenticated), "Access denied" plus "do not have permission" (unauthorized), and "Access forbidden" (forbidden).
- `[data-testid="auth-sign-in"]` appears only for `unauthenticated`; `[data-testid="auth-refresh"]` appears for `forbidden`/`unauthorized`; `[data-testid="auth-org"]`/`[data-testid="auth-project"]` render the organization/project selection surface.
- For local `auth_modes:["none"]` gateways, `[data-testid="auth-placeholder"]` is absent and `.os-task-graph-panel` renders with `data-auth-state="open"`.

These DOM assertions are the runtime evidence for the new user-facing states. A screenshot/video capture is not produced in this headless unattended environment; the assertions above exercise the real `renderAuthPlaceholder` / `renderViewContent` code paths end-to-end through the shared shell.

### Captured rendered DOM (real shell, jsdom)

The following is actual captured output from mounting the real shared shell (`renderOpenSymphonyApp`, `mode:"web"`) against a `MockGatewayTransport` that simulates a hosted gateway rejecting the snapshot, plus a local `auth_modes:["none"]` gateway. Reproduce with `npx jest packages/ui-core/__tests__/auth-states.test.ts` (and a temporary DOM-dump harness over `renderOpenSymphonyApp`).

LOCAL `auth_modes:["none"]` gateway (snapshot succeeds):
```
data-auth-state = open
auth-placeholder present = false
task-graph-panel present = true
<section class="os-panel os-task-graph-panel">...<div class="os-empty">No task graph loaded</div></section>
```

Hosted gateway, snapshot rejected with HTTP 401 (`unauthenticated`):
```
data-auth-state = unauthenticated
auth-placeholder present = true   (data-auth-state="unauthenticated")
auth-sign-in present = true  auth-refresh present = true  auth-org/project present = true
task-graph-panel present = false
<section class="os-panel os-auth-panel" data-testid="auth-placeholder" data-auth-state="unauthenticated">
  <div class="os-section-head"><h2>Sign in</h2><span>hosted</span></div>
  <p class="os-auth-message" data-testid="auth-message">Sign in required to view this OpenSymphony workspace.</p>
  <div class="os-auth-actions">
    <button data-auth-action="sign-in" data-testid="auth-sign-in">Sign in</button>
    <button data-auth-action="refresh" data-testid="auth-refresh">Retry</button>
  </div>
  <div class="os-auth-scope" data-testid="auth-scope">... Organization / Project selects ...</div>
</section>
```

Hosted gateway, snapshot rejected with HTTP 403 hard deny (`forbidden`):
```
data-auth-state = forbidden
auth-placeholder present = true   (data-auth-state="forbidden")
auth-sign-in present = false  auth-refresh present = true  auth-org/project present = true
<section class="os-panel os-auth-panel os-auth-denied" data-testid="auth-placeholder" data-auth-state="forbidden">
  <h2>Access forbidden</h2>
  <p class="os-auth-message">Access to this workspace is forbidden.</p>
  <button data-testid="auth-refresh">Retry</button>
  <div class="os-auth-scope" data-testid="auth-scope">... Organization / Project selects ...</div>
</section>
```

Hosted gateway, snapshot rejected with HTTP 403 carrying `error_code:"unauthorized"` (`unauthorized` permission denial):
```
data-auth-state = unauthorized
auth-placeholder present = true   (data-auth-state="unauthorized")
auth-sign-in present = false  auth-refresh present = true  auth-org/project present = true
<section class="os-panel os-auth-panel os-auth-denied" data-testid="auth-placeholder" data-auth-state="unauthorized">
  <h2>Access denied</h2>
  <p class="os-auth-message">You are signed in but do not have permission to view this workspace.</p>
  <button data-testid="auth-refresh">Retry</button>
  <div class="os-auth-scope" data-testid="auth-scope">... Organization / Project selects ...</div>
</section>
```

## 4. Fake OpenHands server requirements

The fake server in `opensymphony-testkit` should emulate the minimum runtime contract:

- `POST /api/conversations`
- `GET /api/conversations/{id}`
- `POST /api/conversations/{id}/events`
- `POST /api/conversations/{id}/run`
- `GET /api/conversations/{id}/events/search`
- `/sockets/events/{conversation_id}`

It should be scriptable enough to produce:

- clean success runs
- tool-heavy runs
- failure runs
- per-request `/events/search` snapshots that differ across initial sync and post-ready reconcile
- per-connection WebSocket frame sequences so reconnect attempts can observe different ready/drop behavior
- late terminal events
- duplicated events
- out-of-order timestamps
- dropped WebSocket connections
- restart and reattach scenarios

## 5. Live local acceptance suite

The live local suite proves the MVP runtime path can execute on a prepared
developer machine against the pinned local OpenHands server.

Implemented entrypoints:

- `OPENSYMPHONY_LIVE_OPENHANDS=1 cargo test --test live_local_suite -- --ignored --nocapture --test-threads=1`
- `OPENSYMPHONY_LIVE_OPENHANDS=1 ./scripts/live_e2e.sh`

Required machine inputs:

- `uv`, `git`, `curl`, and Rust 1.97.1 or newer
- `OPENSYMPHONY_OPENHANDS_MODEL`
- `OPENSYMPHONY_OPENHANDS_API_KEY` for the live `doctor` probe
- the provider environment expected by the pinned OpenHands server for normal
  issue-session runs; `scripts/live_e2e.sh` sets `OPENAI_API_KEY` from
  `OPENSYMPHONY_OPENHANDS_API_KEY` only when `OPENAI_API_KEY` is otherwise unset

The repository-owned script performs the full live flow:

- runs `opensymphony doctor --config examples/configs/local-dev.with-live-openhands.yaml --live-openhands`
- launches the pinned local OpenHands server on `OPENSYMPHONY_LIVE_SUITE_SERVER_PORT` (default `8010`)
- runs the ignored `live_local_suite` integration tests serially
- writes logs and scenario artifacts under `target/live-local/<timestamp>/` unless
  `OPENSYMPHONY_LIVE_SUITE_OUTPUT_ROOT` overrides the root

### Scenario A: checklist-driven issue lifecycle

- generate a temp target repo with repo-owned `WORKFLOW.md`, `AGENTS.md`, and a two-step checklist
- populate the issue workspace through the documented `after_create` clone hook
- run one issue through the real `WorkspaceManager` plus `IssueSessionRunner` path
- verify workspace creation, prompt capture, conversation creation, and a deterministic first-run assistant reply

Expected artifacts:

- `lifecycle/summary.json`
- `lifecycle/workspaces/COE-LIVE-273/notes/live-suite-checklist.md`
- `lifecycle/workspaces/COE-LIVE-273/.opensymphony/conversation.json`
- `lifecycle/workspaces/COE-LIVE-273/.opensymphony/generated/session-context.json`

Expected assertions:

- the first run uses the full workflow prompt
- the first run records the exact assistant reply `run 1: workspace-created`
- `.opensymphony/` manifests and prompt captures exist for debugging

The focused terminal-envelope tests additionally use temporary Git remotes to
prove atomic staged publication, target-branch and non-shallow verification,
clean-worktree enforcement, wrong-remote quarantine, collision-resistant
checkout keys, instruction hashing, and repository-only prompt composition.

The parent execution-root fixture uses three temporary remotes, multiple
children in one repository, an actual squash merge, an actual rebase and
fast-forward merge, and a recorded shallow generation. It proves one non-Git
root, one shared-object worktree per canonical repository, exact target and
provider merge-result reachability, unchanged child HEAD/status/manifest bytes,
and rejection of stale generations, missing ancestor leases, ambiguous merge
evidence, dirty children, wrong remotes, arbitrary handles, changed root
requests, runtime-map target repinning, and symlink escapes. It also proves
checkout-local HTTP transport configuration is rejected before credential
exposure; checkout-controlled process filters, fsmonitor, custom hooks paths,
and conditional includes are rejected before parent verification; retained
`post-checkout` hooks do not run during worktree creation; colliding sanitized
parent identifiers remain distinct; and `after_create` cannot turn a parent
root into a Git repository. It also covers parent `after_create`
receipt/reuse/failure behavior and proves a child-controlled direct or
worktree-conditional fsmonitor executable is rejected without running before
the incomplete parent root is rolled back. Terminal cleanup also unregisters
the real integration worktrees while the parent and source generations still
exist, then removes the parent root and proves the same generation can be
prepared again without a stale Git registration. Scheduler regressions prove
capture acknowledgement, parent preparation before descendant removal,
deepest-first receipt recovery, hook-once behavior, exact-generation
tombstones, partial-directory deletion recovery, on-disk checkout generation
validation, completed-parent capture after restart, higher-owner preservation,
failed/canceled retention, and retry of visible cleanup failures. A lower-level
regression proves the
orchestrator Git command overrides checkout-controlled fsmonitor configuration
and default repository hooks at execution time. Focused
OpenHands and Codex tests bind the same logical `parent_multi_checkout` envelope
while preserving truthful `trusted_host` containment and omitting a leaf runtime
envelope.
The parent launch tests re-read project-set integration instructions after the
lifecycle hook boundary and reject changed bytes before harness attachment.

### Scenario B: conversation reuse

- run the same issue a second time against the same workspace
- verify the default `per_issue` policy reuses the same `conversation_id`
- verify continuation guidance is selected instead of a second full prompt
- verify the second deterministic assistant reply appears only after the reused conversation resumes

Expected artifacts:

- `lifecycle/summary.json`
- `lifecycle/workspaces/COE-LIVE-273/.opensymphony/prompts/last-continuation-prompt.md`
- `lifecycle/workspaces/COE-LIVE-273/.opensymphony/logs/git-status-after.txt`

The `git-status-after.txt` artifact comes from the workflow `after_run` hook, so the suite also
proves that worker finalization is routing through the workspace manager's `finish_run` path.

Expected assertions:

- first and second runs report the same `conversation_id`
- `last_prompt_kind` in `conversation.json` becomes `continuation`
- the recorded assistant replies end with:

```text
run 1: workspace-created
run 2: conversation-reused
```

### Scenario C: WebSocket reconnect

- place a local fault-injecting proxy in front of the pinned server
- drop the first WebSocket connection immediately after the readiness barrier
- verify the client reconnects, reconciles, and still observes terminal completion

Expected artifacts:

- `reconnect/summary.json`
- `reconnect/proxy.log`

Expected assertions:

- the proxy records at least two websocket connections
- exactly one injected drop is recorded
- the terminal runtime status is still reached after reconnect
- the final message history includes `OpenSymphony reconnect probe OK`

## 6. Operations

Operational guidance now lives in [operations.md](operations.md).

That document covers:

- `opensymphony init`, `run`, `debug`, `doctor`, and `rehydrate`
- local operator workflows and validation commands
- doctor scope and live probe behavior
- logging, manifests, and recovery inspection
- version pinning, CI, and local safety posture

## ACP stdio client tests

`cargo test-system-duckdb --test acp` includes the executable
`tests/fixtures/acp_services_peer.py` peer. It exercises line ranges and endings,
invalid UTF-8, missing write parents, traversal/symlinks, oversized content,
capability absence, cross-session rejection, UTF-8 terminal truncation, exit
races, release-before-exit, cancellation/reaping, immutable host policy,
advertised configuration changes and an authenticated scoped MCP HTTP attachment.
These deterministic tests establish client behavior; live harness qualification
is tracked separately in OSYM-906.

Run `cargo test-system-duckdb --test acp` for the executable client contract and
`cargo test-system-duckdb --lib acp` for central configuration coverage. The reusable
`tests/fixtures/acp_peer.py` peer validates initialize/authenticate/new/prompt,
process/session cwd equality, capability honesty, credential exclusion,
interleaved updates and callbacks, opaque string/zero IDs, unknown notifications,
unknown updates and stop reasons, cancellation acknowledgement/deadline, malformed
and oversized frames, EOF/crash, output floods, bounded stderr/evidence, and a hung
process tree. Regressions cover cancellation in every setup phase, pre-cancelled
launches, JSON-escaped prompt overflow, missing update payloads, preservation of
whitespace and long code chunks, ACP profile migration, environment alias
scoping, post-submission authentication errors, and opaque-ID debug redaction. Current-thread Tokio
tests check callback/cancellation responsiveness, bind a new session before an
adjacent response/update pair is dispatched, and saturate callback output while
a peer stops reading stdin. Count and encoded-byte budgets cover successful,
unknown and invalid permission callbacks; sequential round trips verify that
completed transport writes release reservations.
The native ACP peer also verifies `elicitation/create` form accept, decline and
cancel responses, private large numeric peer RPC IDs with generated public
binding tokens, disabled Cursor methods, and form-only
capability advertisement. The production scheduler/gateway fixture routes a
permission and a choice form through HTTP action receipts to the blocked peer.
The extension peer verifies a registered outbound request has the host-bound
session ID and permitted `_meta`, returns a structured result, and rejects
unregistered methods, stale runs, and unexpected argument keys. The peer sends
the operation result immediately before prompt completion; a repeated host
regression verifies all correlated results survive that ordering. Cursor
unit and host fixture tests cover plan and todo request ID `0` without a
peer-supplied session ID, the accepted plan and todo result shapes, mismatched
session cancellation, owner-bound accepted-response todo projection, duplicate
ID ambiguity across plan/todo callbacks, visible saturation failure, and
unknown request behavior.
Two separately ignored manual integration tests exercise the authenticated
pinned CLI through the production `SessionHost` plan operator route and todo
response path. These tests require local CLI authentication and are not CI gates.
The host integration suite also checks that a peer-echoed environment credential
is redacted in both the result value and metadata, and that a second batch of
operations cannot bypass the eight pending-reply limit after the first batch
times out.
The redacted wire frames and production-path qualification are recorded in
[ACP extension qualification evidence](acp-extension-evidence.md).
It uses a five-minute tracker interval and processes both callbacks through
worker-update wakeups without another tracker tick.
An un-routed native form receives protocol cancellation without failing its
turn, and a delayed worker-consume regression verifies that a timed-out
operator answer cannot reach the ACP callback after its failure receipt.
The scheduler retains a live request when the backend response queue is full or
an unconsumed answer expires, allowing a new submission. An output-reservation
test verifies that an operator answer is acknowledged only after the ACP input
sink flushes its response frame, and sink failure fails every queued receipt.
An early-finish native peer verifies that a completed prompt wakes the
scheduler and clears its pending request even if callback closure loses the
race, with tracker polling set to five minutes.
The peer writes its round-trip completion marker by atomic replacement after
closing the JSON file, so marker existence means the payload is readable.
Gateway timeout and handler-drop tests verify that delayed commands cannot
cross the scheduler application fence; a claimed command waits for its actual
acknowledgement. A concurrent reservation test holds one ACP SDK enqueue while
another callback responds and verifies output reservation and enqueue order.
The run-loop wake regression queues a callback notification and an operator
command during a selected tick, verifies that tick completes, and then drains
both queued events. A delayed ACP flush regression verifies that the actor can
tick, process a worker wake, and receive shutdown while the acknowledgement is
pending; the scheduler rejects a duplicate response and applies the eventual
receipt through its own completion path. A malformed permission callback produces no waiting event;
the routed production requests do. The shared web/desktop test retains two
form selections after refresh, submits both answers, and drops a refresh that
fetched the answered request before the successful submission.
Native Unix tests replace the bound workspace root after service creation and
verify file reads, atomic writes, and new terminal cwd remain on the original
directory inode. They also swap a pinned terminal directory for an external
symlink before spawn and verify it reads from the original directory. A narrow
`unsafe_code` allowance wraps child-only `pre_exec` registration for `fchdir`;
the repository lint is `deny`, and the closure performs no allocation, locking,
logging or host cwd mutation. Callback tests cancel a file operation queued behind
a blocked filesystem worker and verify no write occurs. Executable peers exercise
partial staged-write cancellation and atomic replacement on native platforms,
ordinary MCP environment values beside secret grants, JSON-escaped file/terminal
responses against smaller response budgets, generic credential-bearing MCP
header arguments with exact wire delivery and masked evidence, a one-turn
prompt response immediately followed by a denied file write, deferred
model-to-mode selection, and rejection of credentials embedded in MCP URLs.
Retained-owner fixtures reject abandoned-session callbacks adjacent to a missing
restoration response, reapply changed model/mode/options before the next prompt,
and keep cancellation/deadline failures ahead of durable submission.
The retained host also blocks the filesystem worker during the durable submission
checkpoint, cancels the accepted prompt, and verifies that no prompt reaches the
peer and the persisted marker closes as `cancelled_before_prompt`. On macOS,
the normal-completion retained fixture repeats short-lived terminal callbacks
through successive prompts while the full host suite runs in parallel, covering
the natural-exit process-group reap race.
The `acp-windows` CI job runs `python scripts/validation/check-acp-windows.py`
on Windows. Its temporary Cargo harness compiles the production Windows process
owner and verifies descendant termination on normal teardown, parent exit,
wait deadline, and dropped futures. It also executes the shared environment
replacement helper against a real child to verify case-insensitive alias
precedence. The shared Windows callback path validator rejects real junctions
for existing reads, nonexistent writes and terminal directories; pinned-handle
tests attempt directory and leaf swaps during I/O and terminal spawn. Windows SDK
bindings support same-directory stage promotion and deletion by
handle. Two small audited unsafe wrappers use synchronous owned handles and
bounded SDK-layout buffers; native tests verify successful atomic replacement,
original preservation on cancellation and promotion errors, stage/parent rename
exclusion, and deletion after an outstanding write handle closes. The temporary
validation harness uses the same deny-by-default unsafe lint as the root crate.
Dependencies are read from the root manifest. On another host,
`--check-target x86_64-pc-windows-gnu` checks compilation with that Rust target
installed; cross-compilation alone does not prove Windows process behavior.
Run `cargo fmt --check` and `cargo clippy-system-duckdb`; dependency changes also
require bundled-mode validation. Vendor interoperability evidence belongs to the
later live-qualification task and must not be inferred from fake-peer tests.

`cargo test-system-duckdb --test acp_session_host` exercises the retained owner
with executable subprocesses: repeated attempts, concurrent issues, live leases,
idle expiry, cancellation/busy fencing, negotiated load/replay and resume, fresh
nonpersistent reset, durable uncertain-submission refusal and stale generations.
Callback integration covers cancellation followed by a fresh turn on the same
process, stale terminal rejection, live configuration and secret-safe host-policy/
MCP grant compatibility checks. Normal-completion tests send adjacent late file
and terminal callbacks, verify rejection while idle and process reaping before
completion, then start a fresh callback epoch. A permission-policy peer checks
that `allow_once` selects the offered option during a turn and cancels a
permission request adjacent to the prompt result, both with and without an
operator route. A saturated two-slot operator event channel test holds two
`Opened` events until both peer callbacks time out, then requires both matching
`Closed` events to arrive while the prompt remains active. Scheduler tests
verify that closure removes the pending interaction and resumes the idle clock.
Pre-prompt tests reject file and
terminal requests after session binding. File and terminal-output tests verify
exact wire contents with structural redaction in retained history and evidence.
Configuration tests check preparation-frame attribution on success, cancellation
and timeout; MCP tests reject query strings and aliased excluded credentials.
The peer verifies that the submitted marker is already on disk when a prompt
arrives. `cargo test-system-duckdb --lib opensymphony_acp::durable::tests` covers
owner locks, process-group loss, the launch checkpoint gap, compatibility bounds,
identity mismatches and legacy manifests. Workspace and control-plane regression
targets remain required for changes to persistence or the host observation seam.

`cargo test-system-duckdb --test run run_dispatches_acp` exercises the actual CLI
against a fake tracker and ACP executable with an unreachable OpenHands endpoint.
It verifies exact cwd, workspace hooks, scoped memory, persisted profile routing,
public capabilities and distinct plan/context/turn usage activity with absent
counters preserved. `cargo test-system-duckdb --lib acp` covers continuation,
profile switching and dry runs, persisted recovery, permission waiting, safe
setup retry, ten concurrent workers, interrupt/abort, unreadable submission
evidence and known-finished versus uncertain owner-loss cleanup. Use `tests/fixtures/acp_worker_peer.py`
for production worker fixtures. Gateway/schema tests include a shared Rust and
TypeScript capability fixture; native OpenHands and Codex regression suites remain
required. Unset ambient `LINEAR_CLIENT_ID` and `LINEAR_CLIENT_SECRET` for fake
tracker suites so local OAuth configuration does not override fixture credentials.

## ACP live acceptance

[ACP live qualification](acp-live-qualification.md) contains reproducible
commands and redacted outcomes for two independent vendor CLIs through tracked
`opensymphony run` paths. The ignored tests assert workspace edits, Cursor
operator decision and cancellation acknowledgement, plus live Cursor/Devin
`session/load` without prompt resend. `cargo test-system-duckdb --test acp`
covers the Devin-observed pre-response update ordering, authoritative
snapshot, and wrong-session rejection. Keep these manual tests separate from
unauthenticated CI and run the full system-DuckDB and Rust/TypeScript schema
checks for changes to the adapter.

<!-- BEGIN OPENSYMPHONY MANAGED MEMORY SYNC -->

## Current model

- COE-252 contributed: PR #10: Implement foundation workflow and scheduler contracts
- COE-253 contributed: PR #19: COE-253: OpenHands Runtime Adapter (merge `911b0b4`)
- COE-254 contributed: PR #6: COE-254: bootstrap tracker, workspace, and orchestration core
- COE-255 contributed: PR #4: COE-255: add control plane and FrankenTUI slice
- COE-256 contributed: PR #1: COE-257: tighten hosted deployment guidance
- COE-258 contributed: PR #83: Add memory init and mapped docs sync

## Important invariants

- Preserve the behavior described in the recent captured changes unless current code and tests show it has changed.
- Use capsule source refs to inspect the original PR or Linear issue when context is ambiguous.

## Operational flow

- No generated diagram requested for this sync.

## Known gotchas

- No area-specific gotchas were inferred from the selected memory.

## Recent changes

- COE-252: Foundation and Contracts
- COE-253: OpenHands Runtime Adapter
- COE-254: Tracker, Workspaces, and Orchestration
- COE-255: Observability and FrankenTUI
- COE-256: Validation and Local Operations
- COE-258: Bootstrap workspace and crate boundaries
- COE-259: Workflow loader and typed config
- COE-260: Domain model and orchestrator state machine
- COE-261: Local agent-server supervisor
- COE-262: REST client and conversation contract
- COE-263: Workspace manager and lifecycle hooks
- COE-264: Linear read adapter and issue normalization
- COE-265: WebSocket event stream, reconciliation, and recovery
- COE-266: Issue session runner
- COE-267: Linear MCP write surface
- COE-268: Orchestrator scheduler, retries, and reconciliation
- COE-269: Control-plane API and snapshot store
- COE-270: Repository harness and generated context artifacts
- COE-271: FrankenTUI operator client
- COE-272: Fake OpenHands server and protocol contract suite
- COE-273: Live local end-to-end suite
- COE-274: CLI packaging, doctor, and local operations docs
- COE-275: Remote agent-server mode and auth hardening
- COE-277: Implement hierarchy-aware task selection
- COE-278: Doctor live probe resolves repo-local OpenHands launcher paths reliably
- COE-279: Reject or propagate unsupported OpenHands agent option passthrough
- COE-280: Support workflow-owned OpenHands auth, provider, and launcher overrides at runtime
- COE-281: Support path-bearing OpenHands base URLs and MCP config at runtime
- COE-282: Support workflow-owned OpenHands conversation reuse policy at runtime
- COE-283: Cache per-state running counts in the orchestrator scheduler
- COE-284: Add orchestrator run command to CLI and make it installable
- COE-287: Add opensymphony debug command for conversational session debugging
- COE-288: Add context condenser support to prevent LLM context window overflow
- COE-294: Detect LLM config changes and rehydrate conversations with updated env vars
- COE-382: Add supply-chain and security audits to CI
- COE-383: Decompose oversized session and TUI modules into focused submodules
- COE-384: Expand error-path tests for Linear client and workspace hooks
- COE-385: Resolve runtime tracking TODO in OpenHands session runner
- COE-386: Wire cargo-llvm-cov coverage reporting and regression floor into CI
- COE-387: Audit tracing spans and diagnostics for secret leakage
- COE-389: Current Gateway Inventory And Vocabulary
- COE-390: Gateway Schemas And Stream Feasibility
- COE-391: Gateway Module, Capabilities, And Dashboard Snapshot
- COE-392: Task Graph, Run Detail, File, And Diff Read APIs
- COE-393: Event Journal And Stream Broker
- COE-394: Frontend Workspace And Shared Schemas
- COE-395: Planning Artifact Schema And Session Service
- COE-396: Action Receipts And Initial Run Actions
- COE-397: Gateway API Client, Transport Adapters, And Reducers
- COE-398: Tauri Shell And Security Capabilities
- COE-399: Linear Read Coverage And Task Graph Cache
- COE-400: OpenHands Event Normalization And Runtime Mirror
- COE-401: Web App Entry And Deployment Modes
- COE-402: App Shell, Dashboard, Task Graph, And Run Views
- COE-403: Terminal And Log Renderer Prototype
- COE-404: Desktop Connection Profiles And Daemon Management
- COE-405: Linear Milestone, Issue, And Sub-Issue Mutations
- COE-406: Repository, Linear, And Research Analysis
- COE-407: Browser Transport And Remote Stream Protocols
- COE-408: Harness Adapter And Capability Model
- COE-409: Desktop Settings, Keychain, And Native Actions
- COE-410: Desktop Local Stream Optimization
- COE-411: Task Graph Editor And Runtime Overlay UI
- COE-412: Runtime Timeline And Terminal/Log Association
- COE-413: Implementation Plan Generator Stage
- COE-414: Diff, Validation, Approval, And Run Action Views
- COE-415: Milestone, Issue, And Sub-Issue Compiler
- COE-416: Dependency Graph And Plan Checks
- COE-417: Planning Workspace UI
- COE-419: Hosted Auth Placeholders And Web Parity
- COE-423: Model And Credential Settings
- COE-425: OpenHands Subscription Credential Adapter
- COE-426: Codex App-Server Prototype And Benchmarks
- COE-428: Model Configuration UI And Routing Metadata
- COE-429: Codex Approvals And Cross-Harness Routing
- COE-434: Long-running harness liveness and scheduler/runtime ownership contract
- COE-435: Long-running run observability fixtures and client-facing diagnostics
- COE-449: Desktop alpha recovery: replace stubs with functional app
- COE-452: DuckDB Prebuilt Developer Build Mode
- COE-453: Non-Interactive Init For Automation
- COE-454: OKF Bundle Schema And Legacy Capsule Mapping
- COE-456: OKF Writer, Lint, And Migration Fixtures
- COE-458: Catalog Reindex And Query Compatibility From OKF
- COE-460: OKF Export, Import, And Visibility Boundaries
- COE-461: Memory Graph DTOs And Gateway Endpoints
- COE-463: Docs Sync And MCP Admin Parity For OKF
- COE-464: Graph Extraction, Metrics, And Community Pipeline
- COE-465: Shared Graph Frontend Package And Reducers
- COE-467: Three.js Graph Renderer And Worker Layouts
- COE-468: Concept Inspector, Search, Filters, And Accessibility Fallback
- COE-469: Live Memory Graph Integration And Privacy Gates
- COE-471: Graph Scale, Visual Regression, And Web/Desktop Hardening
- COE-473: Desktop task graph dependency and run detail parity
- COE-475: ChatGPT OAuth For Codex Harness
- COE-476: Codex Production Harness Enablement
- COE-478: Harden model profile storage and validation follow-ups
- COE-479: Codex Debug Session Resume
- COE-480: Run Detail Metrics And Density
- COE-481: Model Configuration Codex Subscription Follow-Up
- COE-482: TUI Codex Token Usage Accounting
- COE-483: Codex Event Content Summaries
- COE-484: Desktop Live Snapshot And Run Detail Refresh
- COE-485: Harden desktop live event resumption and refresh failure visibility
- COE-486: Harness Interrupt Contract And Run Diagnostics
- COE-487: Desktop Run Detail TUI Parity
- COE-488: Lazy Desktop Launcher Command
- COE-489: OpenHands Agent-Server Interrupt Adapter
- COE-490: Codex App-Server Turn Interrupt Adapter
- COE-491: Desktop Run Detail Action Wiring And Cleanup
- COE-492: Merging Supersedes Human Review Polling
- COE-493: Desktop Operations Integration Hardening
- COE-494: Project Metadata For Operator Issue Snapshots
- COE-495: FrankenTUI Project Headers And Dependency Gutter
- COE-496: Desktop Project Grouping And Collapse
- COE-497: Project Grouping Integration Hardening
- COE-498: Tree-sitter Provider Skeleton And Rust Parsing
- COE-499: Memory Context AST Provider Integration
- COE-500: Query Packs For Supported Agent Languages
- COE-501: Code Intelligence Persistence And Ingestion
- COE-502: Read-Only AST MCP And CLI Tools
- COE-503: Code Intelligence Performance Docs And Hardening
- COE-504: Linear Polling And Rate-Limit Recovery
- COE-505: Add scheduler-side Codex stdio interrupt channel
- COE-506: Invert CodeIntelIndex trait ownership after AST memory integration
- COE-507: Deduplicate query-pack assets for grammar variants
- COE-508: Cache code-intel parsers and compiled query packs
- COE-520: Route desktop Knowledge Graph through native gateway commands
- COE-531: Workspace Shell Graph Hero And Surface State
- COE-532: Symbol Identity Container Chain And Code Read Model
- COE-533: Code Graph DTOs Gateway Routes And Native Commands
- COE-534: Code Graph Frontend Surface Adapters And Inspector
- COE-535: Run Diff Symbol Navigation And Code Overlay
- COE-536: Cross Graph Code Memory And Work Chips
- COE-537: Code Graph Scale Accessibility And Parity Hardening
- COE-540: Canonical Codex Thread Reuse And Workspace Retention
- COE-541: Durable Codex Thread Archive And Debug Recovery
- COE-542: Target Branch Code Index And Revision Snapshots
- COE-543: Workspace Code Overlay And Composite Graph
- COE-544: Indexed Agent Code Context And Retrieval
- COE-545: Edge Delta And Module Topology Diff
- COE-546: Code Graph Bootstrap UX And End-To-End Validation
- COE-547: Central Multi-Repository Config And Safe Migration
- COE-548: Canonical Repository Binding And Task Propagation
- COE-549: Verified Checkouts Instructions And Harness Envelopes
- COE-550: Per-Instance Memory Catalog And Source Migration
- COE-551: Scoped Cross-Repository Memory And Leaf Overlays
- COE-554: Restart-Safe Parent Integration Controller
- COE-555: Parent Repair Review And Merge Lifecycle
- COE-556: Bottom-Up Subtree Cleanup And Recovery
- COE-609: ACP Session Ownership And Durable Recovery
- COE-610: ACP Client Callbacks And Session Configuration
- COE-611: ACP Execution Routing And Worker Integration
- COE-612: ACP Operator Requests And Response Routing
- COE-613: ACP Extensions And Harness Operations
- COE-615: ACP Runtime Conformance And Live Qualification

## Source refs

- COE-252
- COE-253
- COE-254
- COE-255
- COE-256
- COE-258
- COE-259
- COE-260
- COE-261
- COE-262
- COE-263
- COE-264
- COE-265
- COE-266
- COE-267
- COE-268
- COE-269
- COE-270
- COE-271
- COE-272
- COE-273
- COE-274
- COE-275
- COE-277
- COE-278
- COE-279
- COE-280
- COE-281
- COE-282
- COE-283
- COE-284
- COE-287
- COE-288
- COE-294
- COE-382
- COE-383
- COE-384
- COE-385
- COE-386
- COE-387
- COE-389
- COE-390
- COE-391
- COE-392
- COE-393
- COE-394
- COE-395
- COE-396
- COE-397
- COE-398
- COE-399
- COE-400
- COE-401
- COE-402
- COE-403
- COE-404
- COE-405
- COE-406
- COE-407
- COE-408
- COE-409
- COE-410
- COE-411
- COE-412
- COE-413
- COE-414
- COE-415
- COE-416
- COE-417
- COE-419
- COE-423
- COE-425
- COE-426
- COE-428
- COE-429
- COE-434
- COE-435
- COE-449
- COE-452
- COE-453
- COE-454
- COE-456
- COE-458
- COE-460
- COE-461
- COE-463
- COE-464
- COE-465
- COE-467
- COE-468
- COE-469
- COE-471
- COE-473
- COE-475
- COE-476
- COE-478
- COE-479
- COE-480
- COE-481
- COE-482
- COE-483
- COE-484
- COE-485
- COE-486
- COE-487
- COE-488
- COE-489
- COE-490
- COE-491
- COE-492
- COE-493
- COE-494
- COE-495
- COE-496
- COE-497
- COE-498
- COE-499
- COE-500
- COE-501
- COE-502
- COE-503
- COE-504
- COE-505
- COE-506
- COE-507
- COE-508
- COE-520
- COE-531
- COE-532
- COE-533
- COE-534
- COE-535
- COE-536
- COE-537
- COE-540
- COE-541
- COE-542
- COE-543
- COE-544
- COE-545
- COE-546
- COE-547
- COE-548
- COE-549
- COE-550
- COE-551
- COE-554
- COE-555
- COE-556
- COE-609
- COE-610
- COE-611
- COE-612
- COE-613
- COE-615

<!-- END OPENSYMPHONY MANAGED MEMORY SYNC -->