Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion .orgii/skills/dual-instance-verification/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: dual-instance-verification
description: Dual-instance (双机) real-machine verification protocol for ORG2 cloud sync and session sharing. Use before declaring any sharing/sync/collab feature or fix "verified": share/unshare, push/retract, fork/import, comments, member-floor, replay, continuation, or anything touching Org2CloudSyncEngine, collab engines, or the session channel pipeline. Also use when a sharing bug escaped earlier testing, to check which discipline below was skipped.
description: 'Dual-instance (双机) real-machine verification protocol for ORG2 cloud sync and session sharing. Use before declaring any sharing/sync/collab feature or fix "verified": share/unshare, push/retract, fork/import, comments, member-floor, replay, continuation, or anything touching Org2CloudSyncEngine, collab engines, or the session channel pipeline. Also use when a sharing bug escaped earlier testing, to check which discipline below was skipped.'
---

# Dual-Instance Verification (双机实测)
Expand Down Expand Up @@ -96,6 +96,34 @@ instance, and the cloud rows — and every state mutation in between is explaina
observed, named "ingest re-hash convergence", and normalized; the re-hash
WAS the bug. Naming an anomaly is not explaining it.

9. **Native continuation requires production-shaped history AND target-provider
acceptance.** Two real app windows do not make a native-continuation test
real when either the transcript or provider is synthetic. A scenario that
replaces a provider-created transcript with `seedChatEvents` proves only the
cloud/runner state machine. A mock provider proves only dispatch and may not
be described as Codex/Claude compatibility. Before claiming native
continuation verified:
- preserve the source provider's actual role/tool/lifecycle event shapes
through share and import; do not overwrite them with a hand-authored happy
path;
- include real provider lifecycle markers, missing/long tool-call ids, and at
least one paired tool result in the fixture or source history;
- require the selected target provider to accept the materialized transcript
and return a non-empty assistant reply; reading the transcript back through
ORG2's own projector is necessary but not sufficient;
- label mock/stub coverage **STATE-MACHINE ONLY** and record each unrun
source-provider -> target-provider cell as UNCOVERED.

10. **Progressive-import surfaces are separate lifecycle cells.** If history
renders before its session/provenance row commits, exercise submit at the
beginning, middle, and finalizing edge of the download (for example 0%,
29%, 67%, and 99%). A visible composer must either queue the exact draft
until the complete canonical transcript is available or stay disabled with
an explicit reason. It must never fall through to the ordinary adapter for
an `imported-session-*`, materialize a partial transcript, or lose the draft.
A test that naturally waits for unrelated steps before submitting does not
cover this cell.

## Invariant & determinism cells (mandatory additions per run)

Born from the 2026-07-30 reflection on why #608 (rewrite storm), the hollow
Expand Down Expand Up @@ -268,6 +296,23 @@ rollover or the window silently truncates.
earlier install/test cycle may have no surviving local push-state, and the
client rightly refuses to retract what it cannot prove it pushed — those
need a server-side fixture sweep, not more waiting.
- **A self-round-trip mistaken for provider compatibility**: projector ->
materializer -> the same product's reader can preserve the same malformed
interpretation. It proves internal consistency, not that Codex, Claude, or
another target accepts the wire transcript. Pair round-trip checks with one
target-provider request and a real assistant response. Provider-contract
stubs must enforce target limits (including tool-call-id constraints) rather
than accepting arbitrary JSON.
- **A real run overwritten by a deterministic fixture**: launching a genuine
provider session and then replacing its history with hand-authored messages
removes exactly the lifecycle/tool variants native migration must handle.
Such a test may remain as deterministic cloud coverage, but it must be named
STATE-MACHINE ONLY and cannot satisfy the native-continuation gate.
- **Presentation semantics promoted into transcript semantics**: a row rendered
with `displayVariant=tool_call` may be an internal lifecycle marker rather
than a model-issued tool invocation. Portable/native projection must use
canonical action/call identity, exclude product lifecycle rows, and validate
the target provider's identifier constraints before dispatch.

## When NOT to use

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Provider-native conversation continuation audit

Scope: imported My Sessions, Team Session conversation-plane execution, Native
Agent/Claude/Codex materialization, setup selection, native resume, and the
Work Item/Team Chat boundary.

## Acceptance criteria

- [x] No transcript-to-user-prompt or transcript-to-preamble path remains.
- [x] One portable message/tool projection is shared by imported and Cloud
conversation entry points.
- [x] Every offered target has a native writer, existing reader, and strict
native resume identity.
- [x] Claude/Codex materializations live in the provider's ordinary native
store and remain openable by the official CLI/app; the account-isolated
ORG2 runner resolves the same file rather than a duplicate transcript.
- [x] The target transcript is read back and compared before the first turn and
after every canonical-prefix synchronization.
- [x] Runtime, account, model, Agent, workspace, and transcript matching are
symmetric for episode reuse.
- [x] Cloud never receives a credential and never executes an Agent.
- [x] Agent-facing content and user images remain separate from the UI display
projection; oversized Cloud events fail instead of truncating.
- [x] Work Item does not own a continuation implementation.
- [x] TypeScript and Rust compilation checks pass; focused behavioral tests pass.

## Ten-layer audit

| Layer | Element | Verdict | Reason | Suggested change |
| ----------------------- | ------------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| 1. Compilation | TS/Rust boundary | keep with reason | `pnpm typecheck` and `cargo check -p org2 --lib` pass. | None. |
| 2. Dead code/dedup | handoff prompt and cursor helpers | fix | Prompt bootstrap duplicated provider context and violated native resume semantics. | Deleted; all entry points use `nativeConversationMaterializer`. |
| 3. Naming | conversation, episode, native session | keep with reason | Canonical conversation is the visible aggregate; episode is a local provider run; native id belongs to the provider. | Keep these terms in docs and code comments. |
| 4. Semantic overloading | `parentSessionId` | keep with reason | It already expresses durable child ownership and avoids a parallel continuation registry. | Do not add another execution table. |
| 5. Defaults | unsupported CLI / resume failure | fix | A default fresh thread would silently lose history. | Capability allowlist and strict Codex `thread/resume`; fail closed. |
| 6. Core leakage | Cloud/Work Item inside continuation core | fix | The core previously carried source-specific prompt/cursor behavior. | Core accepts only locator, canonical events, and local target; Cloud is an adapter. |
| 7. State/finality | reusable terminal child | keep with reason | A healthy child's native transcript may be an exact semantic prefix of the newer canonical transcript; the missing structured suffix is synchronized before native resume. Existing turn lifecycle generation and durable status prevent stale-terminal completion. | Reject failed or divergent children; never bridge a delta through the user prompt. |
| 8. Wire/serialization | portable IR -> Claude/Codex JSONL | fix | Native files must preserve role/tool pairing, images, ids, and account scope. | Structured Tauri payload, bounded size, atomic JSONL, reader round-trip. |
| 9. Entry parity | imported history / Team fork / Cloud plane | fix | Three entry points previously bootstrapped differently. | All now materialize through the same native boundary before sending. |
| 10. Resolver symmetry | target fingerprint and CLI account | fix | A CLI runtime without its compatible account could bind the wrong native store. | Reuse registry-backed native/CLI account compatibility and match every target field. |

## Entry-point matrix

| Entry point | Canonical read | Native materialize | Reader verify | New-turn dispatch | Visible result |
| ------------------------- | ------------------------------ | --------------------------------------------------------- | --------------------------- | -------------------- | --------------------------- |
| Imported My Session | registered full-history reader | shared materializer / prefix synchronizer | authoritative target reader | normal `sendMessage` | ordinary continued Session |
| Team Session conversation | base + Cloud plane | shared materializer / prefix synchronizer on hidden child | authoritative target reader | normal `sendMessage` | canonical root conversation |
| Explicit legacy Team fork | persisted inherited events | shared materializer on fork Session | authoritative target reader | later normal send | explicit fork Session |

## Resolver matrix

| Field | Setup selection | Persisted Session | Reuse comparison | Native binding |
| ---------------- | ---------------------------- | --------------------- | ----------------------------------------- | -------------------------- |
| Runtime/provider | yes | yes | yes | yes |
| Agent definition | yes | yes | yes | runtime-owned |
| Account | compatible local account | yes | yes | local account runner alias |
| Model | account model | yes | yes | normal runner resolution |
| Workspace | verified local checkout/none | yes | yes | native transcript cwd |
| Transcript | canonical events | provider-native store | equality or strict semantic-prefix growth | existing reader round-trip |

## Removed duplication

- Deleted the Team fork handoff prompt and SessionService first-send wrapper.
- Deleted canonical-delta prompt rendering, cursor hashing, and bootstrap prompt
construction from local continuation.
- Reuses the same execution episode by appending the missing canonical
role/tool suffix in native form; it does not create one episode per remote
turn.
- Reused existing Session rows, parent/child grouping, CLI account ledger,
imported-history readers, turn lifecycle, and setup dialog.
- Reused the providers' ordinary native transcript stores. ORG2's isolated
runner profile points to the same file, so official CLI/app continuation and
ORG2 continuation cannot drift into two copies.
- Kept Team Chat audience routing and Work Item classification outside the
provider continuation core.

## Residual constraints

- Portable conversation fidelity is user/assistant/tool history and
attachments, not provider-private reasoning or process memory.
- The current Cloud event wire rejects an individual event over 64 KiB. It does
not silently truncate a transcript that may later be materialized natively.
- Claude Code and Codex are the only verified External CLI targets in this
change. Other imported providers remain valid sources and become targets only
after adding a native writer plus round-trip and resume tests.
- Native Agent appends structured rows transactionally. Claude Code and Codex
atomically replace only an ORG2-marked materialization in the provider's
ordinary native store, then recreate the account-runner alias and resume the
same native id.
- Claude Desktop needs a small registry sidecar to list a local CLI session.
The sidecar points at the same `cliSessionId`; it does not contain a second
transcript, credentials, MCP secrets, or permission grants. Codex uses its
ordinary rollout discovery/read-repair path; ORG2 does not edit Codex's
private application index.
- Claude Desktop can require an app restart before the new sidecar appears.
Codex can require restart, explicit navigation, or its ordinary read-repair
before an already-running app indexes a new rollout.
- macOS/Linux use a symlink for the runner alias. Windows uses a hard link to
avoid elevated symlink privileges; the Windows fallback still needs a
physical-host smoke test.

## Omnigent comparison

Audit reference: `xhluca/session-migrate` / Omnigent commit
`658fb8bd4d383ff705a4eb9229c0ba3525a1b8f4`.

What ORG2 intentionally learned from it:

- Claude and Codex need actual provider files, not a rendered prompt. In
particular, a synthetic Codex rollout needs `session_meta`, `turn_context`,
model-facing `response_item` records, and UI-facing `event_msg` mirrors.
- Native target support is a capability matrix, not an inference from a source
label. A target is selectable only when write, authoritative read, and strict
resume all exist.

Where ORG2 is stronger for the product's Team/My Session model:

- ORG2 already has one canonical, author-attributed, ordered collaboration
plane. Provider episodes materialize from that plane and publish their tail
back into it; they are not the user-facing conversation identity.
- Different members and devices may use different local provider accounts and
runtimes while the UI remains on one Team Session. Credentials never need to
move to a server-side runner.
- The same portable projection accepts every registered imported-history
reader as a source, and every native writer is verified through the reader
the normal app actually uses.
- ORG2 fails closed. Omnigent still documents text-preamble carry paths for
Cursor and OpenCode; ORG2 does not advertise either target until it can write
and resume their real native history.

Where Omnigent is currently ahead:

- It has implemented more concrete native rebuild targets (including Pi,
Hermes, and Qwen). ORG2's verified External CLI target set in this change is
deliberately narrower: Claude Code and Codex. Extending it means adding an
adapter and its real reader/round-trip/resume proof, not weakening the
invariant.
Loading
Loading